/** biome-ignore-all lint/correctness/useExhaustiveDependencies: <> */

import type {
    IssueResponse,
    OrganisationMemberResponse,
    OrganisationResponse,
    ProjectResponse,
    UserRecord,
} from "@issue/shared";
import { useEffect, useRef, useState } from "react";
import AccountDialog from "@/components/account-dialog";
import { CreateIssue } from "@/components/create-issue";
import { IssueDetailPane } from "@/components/issue-detail-pane";
import { IssuesTable } from "@/components/issues-table";
import LogOutButton from "@/components/log-out-button";
import { OrganisationSelect } from "@/components/organisation-select";
import OrganisationsDialog from "@/components/organisations-dialog";
import { ProjectSelect } from "@/components/project-select";
import { ServerConfigurationDialog } from "@/components/server-configuration-dialog";
import { useAuthenticatedSession } from "@/components/session-provider";
import SmallUserDisplay from "@/components/small-user-display";
import { Button } from "@/components/ui/button";
import {
    DropdownMenu,
    DropdownMenuContent,
    DropdownMenuItem,
    DropdownMenuSeparator,
    DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { ResizablePanel, ResizablePanelGroup, ResizableSeparator } from "@/components/ui/resizable";
import { issue, organisation, project } from "@/lib/server";

const BREATHING_ROOM = 1;

export default function App() {
    const { user } = useAuthenticatedSession();

    const organisationsRef = useRef(false);
    const [organisations, setOrganisations] = useState<OrganisationResponse[]>([]);
    const [selectedOrganisation, setSelectedOrganisation] = useState<OrganisationResponse | null>(null);

    const [projects, setProjects] = useState<ProjectResponse[]>([]);
    const [selectedProject, setSelectedProject] = useState<ProjectResponse | null>(null);

    const [issues, setIssues] = useState<IssueResponse[]>([]);
    const [selectedIssue, setSelectedIssue] = useState<IssueResponse | null>(null);

    const [members, setMembers] = useState<UserRecord[]>([]);

    const refetchOrganisations = async (options?: { selectOrganisationId?: number }) => {
        try {
            await organisation.byUser({
                userId: user.id,
                onSuccess: (data) => {
                    const organisations = data as OrganisationResponse[];
                    organisations.sort((a, b) => a.Organisation.name.localeCompare(b.Organisation.name));
                    setOrganisations(organisations);

                    let selected: OrganisationResponse | null = null;

                    if (options?.selectOrganisationId) {
                        const created = organisations.find(
                            (o) => o.Organisation.id === options.selectOrganisationId,
                        );
                        if (created) {
                            selected = created;
                        }
                    } else {
                        const savedId = localStorage.getItem("selectedOrganisationId");
                        if (savedId) {
                            const saved = organisations.find((o) => o.Organisation.id === Number(savedId));
                            if (saved) {
                                selected = saved;
                            }
                        }
                    }

                    if (!selected) {
                        selected = organisations[0] || null;
                    }

                    setSelectedOrganisation(selected);
                },
                onError: (error) => {
                    console.error("error fetching organisations:", error);
                },
            });
        } catch (err) {
            console.error("error fetching organisations:", err);
        }
    };

    useEffect(() => {
        if (organisationsRef.current) return;
        organisationsRef.current = true;
        void refetchOrganisations();
    }, [user.id]);

    const refetchProjects = async (organisationId: number, options?: { selectProjectId?: number }) => {
        try {
            await project.byOrganisation({
                organisationId,
                onSuccess: (data) => {
                    const projects = data as ProjectResponse[];
                    projects.sort((a, b) => a.Project.name.localeCompare(b.Project.name));
                    setProjects(projects);

                    let selected: ProjectResponse | null = null;

                    if (options?.selectProjectId) {
                        const created = projects.find((p) => p.Project.id === options.selectProjectId);
                        if (created) {
                            selected = created;
                        }
                    } else {
                        const savedId = localStorage.getItem("selectedProjectId");
                        if (savedId) {
                            const saved = projects.find((p) => p.Project.id === Number(savedId));
                            if (saved) {
                                selected = saved;
                            }
                        }
                    }

                    if (!selected) {
                        selected = projects[0] || null;
                    }

                    setSelectedProject(selected);
                },
                onError: (error) => {
                    console.error("error fetching projects:", error);
                },
            });
        } catch (err) {
            console.error("error fetching projects:", err);
            setProjects([]);
        }
    };

    const refetchMembers = async (organisationId: number) => {
        try {
            await organisation.members({
                organisationId,
                onSuccess: (data: OrganisationMemberResponse[]) => {
                    setMembers(data.map((m) => m.User));
                },
                onError: (error) => {
                    console.error("error fetching members:", error);
                    setMembers([]);
                },
            });
        } catch (err) {
            console.error("error fetching members:", err);
            setMembers([]);
        }
    };

    // fetch projects when organisation is selected
    useEffect(() => {
        setProjects([]);
        setSelectedProject(null);
        setSelectedIssue(null);
        setIssues([]);
        setMembers([]);
        if (!selectedOrganisation) {
            return;
        }

        void refetchProjects(selectedOrganisation.Organisation.id);
        void refetchMembers(selectedOrganisation.Organisation.id);
    }, [selectedOrganisation]);

    const refetchIssues = async () => {
        try {
            await issue.byProject({
                projectId: selectedProject?.Project.id || 0,
                onSuccess: (data) => {
                    const issues = data as IssueResponse[];
                    issues.reverse(); // newest at the bottom, but if the order has been rearranged, respect that
                    setIssues(issues);
                },
                onError: (error) => {
                    console.error("error fetching issues:", error);
                    setIssues([]);
                },
            });
        } catch (err) {
            console.error("error fetching issues:", err);
            setIssues([]);
        }
    };

    const handleIssueDelete = async (issueId: number) => {
        setSelectedIssue(null);
        setIssues((prev) => prev.filter((issue) => issue.Issue.id !== issueId));
        await refetchIssues();
    };

    // fetch issues when project is selected
    useEffect(() => {
        if (!selectedProject) return;

        void refetchIssues();
    }, [selectedProject]);

    return (
        <main className={`w-full h-screen flex flex-col gap-${BREATHING_ROOM} p-${BREATHING_ROOM}`}>
            {/* header area */}
            <div className="flex gap-12 items-center justify-between">
                <div className={`flex gap-${BREATHING_ROOM} items-center`}>
                    {/* organisation selection */}
                    <OrganisationSelect
                        organisations={organisations}
                        selectedOrganisation={selectedOrganisation}
                        onSelectedOrganisationChange={(org) => {
                            setSelectedOrganisation(org);
                            localStorage.setItem("selectedOrganisationId", `${org?.Organisation.id}`);
                        }}
                        onCreateOrganisation={async (organisationId) => {
                            await refetchOrganisations({ selectOrganisationId: organisationId });
                        }}
                        showLabel
                    />

                    {/* project selection - only shown when organisation is selected */}
                    {selectedOrganisation && (
                        <ProjectSelect
                            projects={projects}
                            selectedProject={selectedProject}
                            organisationId={selectedOrganisation?.Organisation.id}
                            onSelectedProjectChange={(project) => {
                                setSelectedProject(project);
                                localStorage.setItem("selectedProjectId", `${project?.Project.id}`);
                                setSelectedIssue(null);
                            }}
                            onCreateProject={async (projectId) => {
                                if (!selectedOrganisation) return;
                                await refetchProjects(selectedOrganisation.Organisation.id, {
                                    selectProjectId: projectId,
                                });
                            }}
                            showLabel
                        />
                    )}
                    {selectedOrganisation && selectedProject && (
                        <CreateIssue
                            projectId={selectedProject?.Project.id}
                            members={members}
                            statuses={selectedOrganisation.Organisation.statuses}
                            completeAction={async () => {
                                if (!selectedProject) return;
                                await refetchIssues();
                            }}
                        />
                    )}
                </div>
                <div className={`flex gap-${BREATHING_ROOM} items-center`}>
                    <DropdownMenu>
                        <DropdownMenuTrigger className="text-sm">
                            <SmallUserDisplay user={user} />
                        </DropdownMenuTrigger>
                        <DropdownMenuContent align={"end"}>
                            <DropdownMenuItem asChild className="flex items-end justify-end">
                                <AccountDialog />
                            </DropdownMenuItem>
                            <DropdownMenuItem asChild className="flex items-end justify-end">
                                <OrganisationsDialog
                                    organisations={organisations}
                                    selectedOrganisation={selectedOrganisation}
                                    setSelectedOrganisation={setSelectedOrganisation}
                                    refetchOrganisations={refetchOrganisations}
                                />
                            </DropdownMenuItem>
                            <DropdownMenuItem asChild className="flex items-end justify-end">
                                <ServerConfigurationDialog
                                    trigger={
                                        <Button
                                            variant="ghost"
                                            className="flex w-full items-center justify-end text-end px-2 py-1 m-0 h-auto"
                                            title="Server Configuration"
                                        >
                                            Server Configuration
                                        </Button>
                                    }
                                />
                            </DropdownMenuItem>
                            <DropdownMenuSeparator />
                            <DropdownMenuItem className="flex items-end justify-end p-0 m-0">
                                <LogOutButton noStyle className={"flex w-full justify-end"} />
                            </DropdownMenuItem>
                        </DropdownMenuContent>
                    </DropdownMenu>
                </div>
            </div>

            {/* main body */}
            {selectedOrganisation && selectedProject && issues.length > 0 && (
                <ResizablePanelGroup className={`flex-1`}>
                    <ResizablePanel id={"left"} minSize={400}>
                        {/* issues list (table) */}
                        <IssuesTable
                            issuesData={issues}
                            columns={{ description: false }}
                            statuses={selectedOrganisation.Organisation.statuses}
                            issueSelectAction={(issue) => {
                                if (issue.Issue.id === selectedIssue?.Issue.id) setSelectedIssue(null);
                                else setSelectedIssue(issue);
                            }}
                            className="border w-full flex-shrink"
                        />
                    </ResizablePanel>

                    {/* issue detail pane */}
                    {selectedIssue && selectedOrganisation && (
                        <>
                            <ResizableSeparator />
                            <ResizablePanel id={"right"} defaultSize={"30%"} minSize={360} maxSize={"60%"}>
                                <div className="border">
                                    <IssueDetailPane
                                        project={selectedProject}
                                        issueData={selectedIssue}
                                        members={members}
                                        statuses={selectedOrganisation.Organisation.statuses}
                                        close={() => setSelectedIssue(null)}
                                        onIssueUpdate={refetchIssues}
                                        onIssueDelete={handleIssueDelete}
                                    />
                                </div>
                            </ResizablePanel>
                        </>
                    )}
                </ResizablePanelGroup>
            )}
        </main>
    );
}
