import React, { useState, useEffect, useContext } from "react";
import { makeStyles } from "@material-ui/core/styles";
import { blue, yellow } from "@material-ui/core/colors";
import Modal from "@material-ui/core/Modal";
import Backdrop from "@material-ui/core/Backdrop";
import Fade from "@material-ui/core/Fade";
import Fab from "@material-ui/core/Fab";
import Tooltip from "@material-ui/core/Tooltip";
import FormatListBulletedIcon from "@material-ui/icons/FormatListBulleted";
import CalendarTodayIcon from "@material-ui/icons/CalendarToday";
import ScoreIcon from "@material-ui/icons/Score";
import AddIcon from "@material-ui/icons/Add";
import PieChartIcon from "@material-ui/icons/PieChart";
import ModalContent from "../../ModalContent";
import Points from "../../Points";
import Streak from "../../Streak";
import ProductivityScore from "../../ProductivityScore";
import CalendarComponent from "./CalendarComponent";
import CalendarListView from "./CalendarListView";
import UserStats from "../../UserStats";
import Header from "../Header";
import { ThemeContext } from "../../../context/ThemeContext";
import { addTaskToSchedule } from "./TaskScheduler";
import DotoService from "../../../helpers/DotoService";
import "./Calendar.css";
import "../Pages.css";
import { v4 as uuidv4 } from "uuid";
import { Themes } from "../../../constants/Themes";
import { ActiveHoursContext } from "../../../context/ActiveHoursContext";

const classnames = require("classnames");

// This file bases the basic functionality of a calendar page, rendering a calendar with relevant added tasks.
// Also handling list view of tasks to-do-today
const useStyles = makeStyles(theme => ({
    modal: {
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
    },
    paper: {
        backgroundColor: theme.palette.background.paper,
        border: "2px solid #000",
        boxShadow: theme.shadows[5],
        padding: theme.spacing(2, 4, 3),
    },
    blue: {
        color: theme.palette.getContrastText(blue[500]),
        backgroundColor: blue[500],
        boxShadow: theme.shadows[5],
    },
    shadow: {
        color: theme.palette.getContrastText(yellow[500]),
        boxShadow: theme.shadows[5],
        borderRadius: "50%",
    },
}));

const Calendar = () => {
    var streakRef = React.createRef();

    const classes = useStyles();
    const [listView, setListView] = useState();
    const [isOpenScore, setIsOpenScore] = useState(false);
    const [tasks, setTasks] = useState([]);
    const [open, setOpen] = useState(false);
    const [statsOpen, setStatsOpen] = useState(false);
    const [theme, setTheme] = useContext(ThemeContext);
    const [priorityStats, setPriorityStats] = useState([]);
    const [userPoints, setUserPoints] = useState(0);
    const { activeHoursStart, activeHoursEnd } = useContext(ActiveHoursContext);
    const [startTime, setStartTime] = activeHoursStart;
    const [endTime, setEndTime] = activeHoursEnd;

    const handleIsScoreOpen = () => {
        if (isOpenScore) {
            setIsOpenScore(false);
        } else {
            setIsOpenScore(true);
        }
    };

    const handleOpen = () => {
        setOpen(true);
    };

    const handleClose = () => {
        setOpen(false);
    };

    const handleStatsOpen = () => {
        if (statsOpen) {
            setStatsOpen(false);
        } else {
            var medTasks = tasks.filter(function(task) {
                return task.priority === 20 && task.isComplete;
            });
            var lowTasks = tasks.filter(function(task) {
                return task.priority === 30 && task.isComplete;
            });
            var highTasks = tasks.filter(function(task) {
                return task.priority === 10 && task.isComplete;
            });
            setPriorityStats([highTasks.length, medTasks.length, lowTasks.length]);
            setStatsOpen(true);
        }
    };

    useEffect(() => {
        const fetchTasks = async () => {
            const tasks = await DotoService.getTasks();
            setTasks(tasks);
        };
        const fetchUserInfo = async () => {
            const userInfo = await DotoService.getUserInfo();
            setTheme(userInfo.themePreference);
            setUserPoints(userInfo.points);
            setStartTime(userInfo.startTime);
            setEndTime(userInfo.endTime);
        };
        fetchUserInfo();
        fetchTasks();
    }, [setTheme, setStartTime, setEndTime]);

    // Adds new task based on input fields from Modal
    const addNewTask = async newTask => {
        const { newTaskOrder, updatedTask } = addTaskToSchedule(newTask, tasks, new Date(startTime), new Date(endTime));
        newTask.taskId = uuidv4();
        newTask.id = newTask.taskId;
        setTasks(newTaskOrder);
        handleClose();
        await DotoService.setNewTask(updatedTask);
    };

    const deleteTask = async taskId => {
        const taskList = [...tasks];
        const index = taskList.findIndex(task => task.taskId === taskId);
        taskList.splice(index, 1);
        setTasks(taskList);

        await DotoService.deleteTask(taskId);
    };

    const changePoints = change => {
        DotoService.updateUserInfo({ points: userPoints + change });
        setUserPoints(userPoints + change);
    };

    const handleTaskStatusUpdated = taskId => {
        const newTasks = [...tasks];
        const taskToUpdate = newTasks.find(task => task.taskId === taskId);

        // update points
        // if duration is passed in, use that, otherwise calculate it from start and end dates
        const minutes = taskToUpdate.duration
            ? taskToUpdate.duration
            : Math.abs(taskToUpdate.startDate - taskToUpdate.endDate) / 1000 / 60;
        // if task is completed, increase points, otherwise, decrease points
        taskToUpdate.isComplete ? changePoints(-minutes) : changePoints(minutes);

        // update task
        taskToUpdate.isComplete = !taskToUpdate.isComplete;
        DotoService.updateTask(taskToUpdate);
        setTasks(newTasks);

        // update streak
        streakRef.current.updateStreak();
    };

    const handleTaskUpdated = async task => {
        const taskList = [...tasks];
        const index = taskList.findIndex(currentTask => currentTask.taskId === task.taskId);
        taskList.splice(index, 1);
        const { newTaskOrder, updatedTask } = addTaskToSchedule(task, taskList, new Date(startTime), new Date(endTime));
        setTasks(newTaskOrder);
        await DotoService.deleteTask(task.taskId);
        await DotoService.setNewTask(updatedTask);
        document.getElementById("grid").click(); // Debt: force close tool tip due to state not being updated
    };

    const onCommitChanges = ({ added, changed, deleted }) => {
        // Currently adding and deleting are both no-ops
        // TODO - consider refactoring adding and deleting to use built-in components and pass logic through here
        if (changed) {
            const updatedTasks = tasks.map(task => {
                if (changed[task.id]) {
                    const { startDate: newStartDate } = changed[task.id];
                    const { reminderDate, startDate: oldStartDate } = task;
                    if (newStartDate && reminderDate) {
                        // Offset the reminder date by the difference of the start dates
                        task.reminderDate = new Date(reminderDate.getTime() + (newStartDate - oldStartDate));
                    }
                    const updatedTask = { ...task, ...changed[task.id] };
                    updatedTask.duration = Math.ceil((updatedTask.endDate - updatedTask.startDate) / 60000);
                    DotoService.updateTask(updatedTask);
                    return updatedTask;
                }
                return task;
            });
            updatedTasks.sort((a, b) => a.startDate - b.startDate);
            setTasks(updatedTasks);
        }
    };

    return (
        <div className="page-layout">
            <div
                className={classnames(
                    "left-side-bar",
                    theme === Themes.DARK ? "left-side-bg-blue" : "left-side-bg-green",
                )}
            />
            <div className="calendar-buttons">
                <div className="mb-3">
                    <Tooltip title="Add Task">
                        <Fab onClick={handleOpen} size="small">
                            <AddIcon />
                        </Fab>
                    </Tooltip>
                </div>
                <div className="mb-3">
                    <Tooltip title="List View">
                        <Fab onClick={() => setListView(!listView)} size="small">
                            {listView ? <CalendarTodayIcon /> : <FormatListBulletedIcon />}
                        </Fab>
                    </Tooltip>
                </div>
                <div className="mb-3">
                    <Tooltip title="View Your Stats">
                        <Fab onClick={handleStatsOpen} size="small">
                            <PieChartIcon />
                        </Fab>
                    </Tooltip>
                </div>
                <div className="mb-3">
                    <Tooltip title="Productivity Score View">
                        <Fab onClick={handleIsScoreOpen} size="small">
                            <ScoreIcon />
                        </Fab>
                    </Tooltip>
                </div>
                <div>
                    <h2>Points</h2>
                    <Points avatarClass={classes.blue} value={userPoints} />
                </div>
                <div>
                    <Streak tasks={[...tasks]} ref={streakRef} />
                </div>
            </div>
            <span className="content-container">
                <Header title="Calendar" />
                <div className="flex">
                    <div className="calendar-component">
                        <CalendarComponent
                            tasks={tasks}
                            onTaskDeleted={deleteTask}
                            onTaskStatusUpdated={handleTaskStatusUpdated}
                            onTaskUpdated={handleTaskUpdated}
                            onCommitChanges={onCommitChanges}
                        />
                    </div>
                    {listView && <CalendarListView tasks={tasks} onTaskStatusUpdated={handleTaskStatusUpdated} />}
                </div>
                <Modal
                    aria-labelledby="transition-modal-title"
                    aria-describedby="transition-modal-description"
                    className={classes.modal}
                    open={open}
                    onClose={handleClose}
                    closeAfterTransition
                    BackdropComponent={Backdrop}
                    BackdropProps={{
                        timeout: 500,
                    }}
                >
                    {/* Transition effects for list view of to-do tasks for today */}
                    <Fade in={open}>
                        <div className={classes.paper}>
                            <ModalContent addNewTask={addNewTask} modalBackground={theme} />
                        </div>
                    </Fade>
                </Modal>
                <Modal
                    aria-labelledby="stats-modal"
                    aria-describedby="transition-modal-description"
                    className={classes.modal}
                    open={statsOpen}
                    onClose={handleStatsOpen}
                    closeAfterTransition
                    BackdropComponent={Backdrop}
                    BackdropProps={{
                        timeout: 500,
                    }}
                >
                    <Fade in={statsOpen}>
                        <div className={classes.paper}>
                            <UserStats
                                modalBackground={theme}
                                // TODO: get real values for these.
                                hoursWorked="10.5"
                                dayRecord="4"
                                priorityStats={priorityStats}
                            />
                        </div>
                    </Fade>
                </Modal>
                <Modal
                    aria-labelledby="transition-modal-title"
                    aria-describedby="transition-modal-description"
                    className={classes.modal}
                    open={isOpenScore}
                    onClose={handleIsScoreOpen}
                    closeAfterTransition
                    BackdropComponent={Backdrop}
                    BackdropProps={{
                        timeout: 500,
                    }}
                >
                    {/* Transition effects for list view of to-do tasks for today */}
                    <Fade in={isOpenScore}>
                        <div className={classes.paper}>
                            <ProductivityScore />
                        </div>
                    </Fade>
                </Modal>
            </span>
        </div>
    );
};

export default Calendar;