import "../style/home/home.css"
import { useNavigate } from "react-router-dom"
import { createContext, Dispatch, useCallback, useContext, useEffect, useMemo, useReducer } from "react"
import { useAppFetcher } from "../App.tsx"
import { Visualizer } from "../components/Visualizer.tsx"
import BinSvg from "../assets/icon/bin.svg?react"
import ExportSvg from "../assets/icon/export.svg?react"
import DuplicateSvg from "../assets/icon/duplicate.svg?react"
import ExportTacticPopup from "./popup/ExportTacticPopup.tsx"
import { APITacticService } from "../service/APITacticService.ts"
import { FileUploader } from "react-drag-drop-files"
import { importTactic, importTacticFromFile, loadPlainTactic } from "../domains/TacticPersistenceDomain.ts"

interface Tactic {
    id: number
    name: string
    creationDate: number
}

interface Team {
    id: number
    name: string
    picture: string
    main_color: string
    second_color: string
}

enum HomePageStateActionKind {
    UPDATE_TACTICS = "UPDATE_TACTICS",
    ADD_TACTIC = "ADD_TACTIC",
    REMOVE_TACTIC = "REMOVE_TACTIC",
    UPDATE_TEAMS = "UPDATE_TEAMS",
    SET_EXPORTING_TACTIC = "SET_EXPORTING_TACTIC",
    INIT = "INIT",
}

type HomePageStateAction =
    | {
    type: HomePageStateActionKind.UPDATE_TACTICS
    tactics: Tactic[]
}
    | {
    type: HomePageStateActionKind.UPDATE_TEAMS
    teams: Team[]
}
    | {
    type: HomePageStateActionKind.INIT
    state: HomePageState
}
    | {
    type: HomePageStateActionKind.SET_EXPORTING_TACTIC
    tacticId: number | undefined
}
    | {
    type: HomePageStateActionKind.REMOVE_TACTIC,
    tacticId: number
} | {
    type: HomePageStateActionKind.ADD_TACTIC,
    tactic: Tactic
}

interface HomePageState {
    tactics: Tactic[]
    teams: Team[]
    /**
     * The home page displays a popup to export a certains tactic
     */
    exportingTacticId?: number
}

function homePageStateReducer(
    state: HomePageState,
    action: HomePageStateAction,
): HomePageState {
    switch (action.type) {
        case HomePageStateActionKind.UPDATE_TACTICS:
            return { ...state, tactics: action.tactics }

        case HomePageStateActionKind.UPDATE_TEAMS:
            return { ...state, teams: action.teams }

        case HomePageStateActionKind.SET_EXPORTING_TACTIC:
            return { ...state, exportingTacticId: action.tacticId }

        case HomePageStateActionKind.ADD_TACTIC:
            return { ...state, tactics: [action.tactic, ...state.tactics] }

        case HomePageStateActionKind.REMOVE_TACTIC:
            return { ...state, tactics: state.tactics.filter(t => t.id !== action.tacticId) }

        case HomePageStateActionKind.INIT:
            return action.state
    }
}

interface HomeStateContextMutable {
    state: HomePageState
    dispatch: Dispatch<HomePageStateAction>
}

const HomeStateContext = createContext<HomeStateContextMutable | null>(null)

function useHomeState() {
    return useContext(HomeStateContext)
}

export default function HomePage() {
    const [state, dispatch] = useReducer(homePageStateReducer, {
        tactics: [],
        teams: [],
    })

    const navigate = useNavigate()
    const fetcher = useAppFetcher()

    useEffect(() => {
        async function initUserData() {
            const response = await fetcher.fetchAPIGet("user-data")

            if (response.status == 401) {
                navigate("/login")
                return // if unauthorized
            }
            type UserDataResponse = { teams: Team[]; tactics: Tactic[] }
            const { teams, tactics }: UserDataResponse = await response.json()
            tactics.sort((a, b) => b.creationDate - a.creationDate)
            dispatch({
                type: HomePageStateActionKind.INIT,
                state: { teams, tactics },
            })
        }

        initUserData()
    }, [fetcher, navigate])

    const tacticExportService = useMemo(
        () =>
            state.exportingTacticId
                ? new APITacticService(fetcher, state.exportingTacticId!)
                : null,
        [fetcher, state.exportingTacticId],
    )

    return (
        <HomeStateContext.Provider value={{ state, dispatch }}>
            {tacticExportService && (
                <div id="exports-popup">
                    <ExportTacticPopup
                        service={tacticExportService}
                        onHide={() =>
                            dispatch({
                                type: HomePageStateActionKind.SET_EXPORTING_TACTIC,
                                tacticId: undefined,
                            })
                        }
                    />
                </div>
            )}
            <Home />
        </HomeStateContext.Provider>
    )
}

function Home() {
    return (
        <div id="main">
            <Body />
        </div>
    )
}

function Body() {
    const widthPersonalSpace = 78
    const widthSideMenu = 100 - widthPersonalSpace
    return (
        <div id="body">
            <PersonalSpace width={widthPersonalSpace} />
            <SideMenu width={widthSideMenu} />
        </div>
    )
}

function SideMenu({ width }: { width: number }) {
    return (
        <div
            id="side-menu"
            style={{
                width: width + "%",
            }}>
            <div id="side-menu-content">
                <LastTeamsSideMenu />
                <LastTacticsSideMenu />
                <TacticImportArea />
            </div>
        </div>
    )
}

function TacticImportArea() {
    const fetcher = useAppFetcher()
    const { dispatch } = useHomeState()!

    const handleDrop = useCallback(
        async (file: File) => {
            importTacticFromFile(fetcher, file, (tactic) => {
                dispatch({
                    type: HomePageStateActionKind.ADD_TACTIC,
                    tactic: {
                        name: tactic.name,
                        id: tactic.id,
                        creationDate: new Date().getDate(),
                    },
                })
            })
        },
        [dispatch, fetcher],
    )

    return (
        <div id="tactic-import-area">
            <FileUploader
                handleChange={handleDrop}
                types={["json"]}
                hoverTitle="Déposez ici"
                label="Séléctionnez ou déposez un fichier ici"/>
        </div>
    )
}

function PersonalSpace({ width }: { width: number }) {
    return (
        <div
            id="personal-space"
            style={{
                width: width + "%",
            }}>
            <TitlePersonalSpace />
            <BodyPersonalSpace />
        </div>
    )
}

function TitlePersonalSpace() {
    return (
        <div id="title-personal-space">
            <h2>Espace Personnel</h2>
        </div>
    )
}

function TacticGrid({ tactics }: { tactics: Tactic[] }) {
    return (
        <div id={"tactics-grid"}>
            {tactics.map((team) => (
                <TacticCard key={team.id} tactic={team} />
            ))}
        </div>
    )
}

function TacticCard({ tactic }: { tactic: Tactic }) {
    const navigate = useNavigate()
    const fetcher = useAppFetcher()
    const {
        dispatch,
    } = useHomeState()!
    return (
        <div
            className={"tactic-card"}
            onClick={() => navigate(`/tactic/${tactic.id}/edit`)}>
            <div className={"tactic-card-preview"}>
                <Visualizer
                    visualizerId={tactic.id.toString()}
                    tacticId={tactic.id}
                />
            </div>
            <div className="tactic-card-content">
                <p className="tactic-card-title">{tactic.name}</p>
                <div className="tactic-card-actions">
                    <ExportSvg
                        className="tactic-card-export-btn"
                        onClick={(e) => {
                            e.stopPropagation()
                            dispatch({
                                type: HomePageStateActionKind.SET_EXPORTING_TACTIC,
                                tacticId: tactic.id,
                            })
                        }}
                    />
                    <BinSvg
                        className="tactic-card-remove-btn"
                        onClick={async (e) => {
                            e.stopPropagation()
                            const response = await fetcher.fetchAPI(
                                `tactics/${tactic.id}`,
                                {},
                                "DELETE",
                            )
                            if (!response.ok) {
                                throw Error(
                                    `Cannot delete tactic ${tactic.id}!`,
                                )
                            }
                            dispatch({
                                type: HomePageStateActionKind.REMOVE_TACTIC,
                                tacticId: tactic.id,
                            })
                        }}
                    />
                    <DuplicateSvg
                        className="tactic-card-duplicate-btn"
                        onClick={async (e) => {
                            e.stopPropagation()
                            const service = new APITacticService(
                                fetcher,
                                tactic.id,
                            )
                            const context = await service.getContext()
                            if (typeof context === "string")
                                throw Error(context)

                            const plainTactic = await loadPlainTactic(
                                context,
                                service,
                            )
                            const { name, id } = await importTactic(
                                fetcher,
                                plainTactic,
                            )

                            dispatch({
                                type: HomePageStateActionKind.ADD_TACTIC,
                                tactic: { name, id, creationDate: 0 },
                            })
                        }}
                    />
                </div>
            </div>
        </div>
    )
}

function BodyPersonalSpace() {
    const tactics = useHomeState()!.state.tactics
    return (
        <div id="body-personal-space">
            {tactics.length == 0 ? (
                <p>Aucune tactique créée !</p>
            ) : (
                <TacticGrid tactics={tactics} />
            )}
        </div>
    )
}

function LastTeamsSideMenu() {
    const navigate = useNavigate()
    return (
        <div id="teams">
            <div className="titre-side-menu">
                <h2 className="title">Mes équipes</h2>
                <button className="new" onClick={() => navigate("/team/new")}>
                    +
                </button>
            </div>
            <SetButtonTeam />
        </div>
    )
}

function LastTacticsSideMenu() {
    const navigate = useNavigate()

    return (
        <div id="tactic">
            <div className="titre-side-menu">
                <h2 className="title">Mes dernières tactiques</h2>
                <button
                    className="new"
                    id="create-tactic"
                    onClick={() => navigate("/tactic/new")}>
                    +
                </button>
            </div>
            <SetButtonTactic />
        </div>
    )
}

function SetButtonTactic() {
    const tactics = useHomeState()!.state.tactics.slice(0, 5)
    const lastTactics = tactics.map((tactic) => (
        <LastTacticCard key={tactic.id} tactic={tactic} />
    ))
    return <div className="set-button">{lastTactics}</div>
}

function SetButtonTeam() {
    const teams = useHomeState()!.state.teams

    const listTeam = teams.map((team) => <TeamCard key={team.id} team={team} />)
    return <div className="set-button">{listTeam}</div>
}

function TeamCard({ team }: { team: Team }) {
    const name = truncateString(team.name, 20)
    const navigate = useNavigate()

    return (
        <div>
            <div
                id={"button-team" + team.id}
                className="button-side-menu data"
                onClick={() => {
                    navigate("/team/" + team.id)
                }}>
                {name}
            </div>
        </div>
    )
}

function LastTacticCard({ tactic }: { tactic: Tactic }) {
    const name = truncateString(tactic.name, 20)
    const navigate = useNavigate()

    return (
        <div
            id={"button" + tactic.id}
            className="button-side-menu data"
            onClick={() => {
                navigate("/tactic/" + tactic.id + "/edit")
            }}>
            {name}
        </div>
    )
}

function truncateString(name: string, limit: number): string {
    if (name.length > limit) {
        name = name.substring(0, limit) + "..."
    }
    return name
}
