import type {Route} from "../../../.react-router/types/app/pages/dashboard/+types/AppointmentManagement";
import {useDisclosure} from "@mantine/hooks";
import {useEffect, useMemo, useState} from "react";
import {BookingCategory, DashboardPageType} from "~/utils/hms_enums.ts";
import {useNavigate, useOutletContext} from "react-router";
import {
    type OutletContextType,
    type PatientBookingInfo,
    type DoctorTeamInfo,
    SORT_SYMBOLS
} from "~/utils/models.ts";
import {Accordion, ActionIcon, Badge, Button, Card, Group, Pagination, Stack, Table, Text} from "@mantine/core";
import {apiGetAllAppointments, get_team_info} from "~/utils/hms_api.ts";
import {showErrorMessage, timestampToDate} from "~/utils/utils.ts";
import {iconMStyle, marginLeftRight, marginRightBottom, marginRound, marginTopBottom, textCenter} from "~/styles.ts";
import CheckCircleIcon from "mdi-react/CheckCircleIcon";
import CancelIcon from "mdi-react/CancelIcon";
import HospitalIcon from "mdi-react/HospitalIcon";
import {
    confirmApproveAppointment,
    confirmRejectAppointment,
    confirmPatientAdmission,
    confirmViewTeamMembers
} from "~/components/subs/confirms.tsx";
import {AppointmentManageFilter} from "~/components/subs/AppointmentManageFilter.tsx";
import HomePlusIcon from "mdi-react/HomePlusIcon";
import {TruncatedText} from "~/components/subs/TruncatedText.tsx";
import InfoIcon from "mdi-react/InfoIcon";
import {PatientInfoDisplay} from "~/components/subs/PatientInfoDisplay.tsx";
import {ResponsiveTableContainer} from "~/components/subs/ResponsiveTableContainer.tsx";

export function meta({}: Route.MetaArgs) {
    return [
        { title: "Appointment Management" },
        { name: "description", content: "Appointment Management" },
    ];
}

export default function Component() {
    const navigate = useNavigate();
    const [refreshingAppointmentList, setRefreshingAppointmentList] = useState<boolean>(false);
    const [appointmentInfo, setAppointmentInfo] = useState<{appointments: PatientBookingInfo[], total_pages: number}>({appointments: [], total_pages: 1});
    const [teamInfoMap, setTeamInfoMap] = useState<Map<number, DoctorTeamInfo>>(new Map());
    const [loadingTeams, setLoadingTeams] = useState<Set<number>>(new Set());

    const [sortKey, setSortKey] = useState<string>("id");
    const [sortDesc, setSortDesc] = useState<boolean>(true);
    const [currPage, setCurrPage] = useState<number>(1);

    const [filterCategories, setFilterCategories] = useState<string[]>([]);
    const [filterStatus, setFilterStatus] = useState<number>(-1);
    const [includeDischarged, setIncludeDischarged] = useState<boolean>(false);

    const { loginUserInfo, refreshMyInfo } = useOutletContext<OutletContextType>();

    useEffect(() => {
        refreshAppointmentList();
    }, []);

    useEffect(() => {
        refreshAppointmentList();
    }, [currPage, includeDischarged]);

    const updateFilter = (categories: string[], status: number, discharged: boolean) => {
        setFilterCategories(categories);
        setFilterStatus(status);
        setIncludeDischarged(discharged);
    };

    const refreshAppointmentList = () => {
        setRefreshingAppointmentList(true);
        apiGetAllAppointments(currPage, includeDischarged).then(res => {
            if (!res.success) {
                showErrorMessage(res.message, "Failed to get appointments list");
                return;
            }
            setAppointmentInfo(res.data);
            
            // Fetch team info for all appointments with assigned teams
            const teamsToFetch = res.data.appointments
                .filter(app => app.assigned_team !== null)
                .map(app => app.assigned_team as number);
            
            // Remove duplicates
            const uniqueTeams = [...new Set(teamsToFetch)];
            
            // Fetch team info for each unique team ID
            uniqueTeams.forEach(teamId => {
                fetchTeamInfo(teamId);
            });
        })
        .catch(err => {})
        .finally(() => { setRefreshingAppointmentList(false); });
    };
    
    const fetchTeamInfo = (teamId: number) => {
        if (teamId === null || teamInfoMap.has(teamId) || loadingTeams.has(teamId)) {
            return;
        }

        setLoadingTeams(prev => new Set([...prev, teamId]));
        
        get_team_info(teamId).then(res => {
            if (res.success) {
                setTeamInfoMap(prev => {
                    const newMap = new Map(prev);
                    newMap.set(teamId, res.data.team);
                    return newMap;
                });
            }
        })
        .catch(err => {})
        .finally(() => {
            setLoadingTeams(prev => {
                const newSet = new Set(prev);
                newSet.delete(teamId);
                return newSet;
            });
        });
    };
    
    const handleViewTeam = (teamId: number) => {
        const teamInfo = teamInfoMap.get(teamId);
        if (teamInfo) {
            confirmViewTeamMembers(teamInfo);
        } else {
            // If team info is not fetched yet, fetch it and then show
            get_team_info(teamId).then(res => {
                if (res.success) {
                    setTeamInfoMap(prev => {
                        const newMap = new Map(prev);
                        newMap.set(teamId, res.data.team);
                        return newMap;
                    });
                    confirmViewTeamMembers(res.data.team);
                } else {
                    showErrorMessage(res.message, "Failed to fetch team information");
                }
            }).catch(err => {
                showErrorMessage("Failed to fetch team information", "Error");
            });
        }
    };

    const handleSort = (key: string) => {
        if (sortKey === key) {
            setSortDesc(!sortDesc);
        } else {
            setSortKey(key);
            setSortDesc(false); // Default ascending
        }
    };

    const sortedAppointments = useMemo(() => {
        let data = [...appointmentInfo.appointments];
        
        // Apply filters
        data = data.filter((appointment) => {
            // Filter by category
            const categoryMatch = filterCategories.length === 0 || filterCategories.includes(appointment.category);
            
            // Filter by status
            let statusMatch = true;
            if (filterStatus !== -1) {
                if (filterStatus === 0) { // Pending
                    statusMatch = !appointment.approved;
                } else if (filterStatus === 1) { // Approved
                    statusMatch = appointment.approved && appointment.assigned_team !== null;
                } else if (filterStatus === 2) { // Rejected
                    statusMatch = appointment.approved && appointment.assigned_team === null;
                }
            }
            
            return categoryMatch && statusMatch;
        });

        // Apply sorting
        if (!sortKey) return data;

        data.sort((a, b) => {
            const valA = a[sortKey];
            const valB = b[sortKey];
            
            if (typeof valA === 'string' && typeof valB === 'string') {
                const cmp = valA.localeCompare(valB);
                return sortDesc ? -cmp : cmp;
            }

            if (typeof valA === 'number' && typeof valB === 'number') {
                return sortDesc ? valB - valA : valA - valB;
            }

            if (typeof valA === 'boolean' && typeof valB === 'boolean') {
                return sortDesc ? (valB ? 1 : -1) : (valA ? 1 : -1);
            }
            
            return 0;
        });
        
        return data;
    }, [appointmentInfo.appointments, sortKey, sortDesc, filterCategories, filterStatus]);

    const handleApproveAppointment = (appointmentId: number) => {
        confirmApproveAppointment(appointmentId, refreshAppointmentList);
    };

    const handleRejectAppointment = (appointmentId: number) => {
        confirmRejectAppointment(appointmentId, refreshAppointmentList);
    };

    const handlePatientAdmission = (appointmentId: number) => {
        confirmPatientAdmission(appointmentId, refreshAppointmentList);
    };

    const getCategoryDisplay = (category: string) => {
        const key = Object.entries(BookingCategory).find(([_, value]) => value === category)?.[0];
        return key ? key.replace(/_/g, ' ') : category;
    };

    const getStatusBadge = (appointment: PatientBookingInfo) => {
        if (appointment.discharged) {
            return <Badge color="purple">Discharged</Badge>;
        } else if (appointment.admitted) {
            return <Badge color="blue">Admitted</Badge>;
        } else if (appointment.approved) {
            if (appointment.assigned_team === null) {
                return <Badge color="red">Rejected</Badge>;
            } else {
                return <Badge color="green">Approved</Badge>;
            }
        } else {
            return <Badge color="yellow">Pending</Badge>;
        }
    };

    const getTeamDisplay = (appointment: PatientBookingInfo) => {
        if (!appointment.approved) {
            return <Text size="sm" c="dimmed">Pending approval</Text>;
        }
        
        if (appointment.assigned_team === null) {
            return <Text size="sm" c="dimmed">Not assigned</Text>;
        }
        
        const teamInfo = teamInfoMap.get(appointment.assigned_team);
        if (!teamInfo) {
            return (
                <Group gap="xs">
                    <Text>ID: {appointment.assigned_team}</Text>
                    <ActionIcon 
                        size="sm"
                        onClick={() => handleViewTeam(appointment.assigned_team as number)}
                        title="View team details"
                    >
                        <InfoIcon style={iconMStyle} />
                    </ActionIcon>
                </Group>
            );
        }
        
        return (
            <Group gap="xs">
                <Text>{teamInfo.department.replace(/_/g, ' ')}</Text>
                <ActionIcon 
                    size="sm"
                    onClick={() => handleViewTeam(appointment.assigned_team as number)}
                    title="View team details"
                >
                    <InfoIcon style={iconMStyle} />
                </ActionIcon>
            </Group>
        );
    };

    const rows = sortedAppointments.map((appointment) => (
        <Table.Tr key={appointment.id}>
            <Table.Td>{appointment.id}</Table.Td>
            <Table.Td>
                <PatientInfoDisplay patientId={appointment.patient_id} />
            </Table.Td>
            <Table.Td>{getCategoryDisplay(appointment.category)}</Table.Td>
            <Table.Td>{new Date(appointment.appointment_time * 1000).toLocaleString('en-GB').replace(',', '')}</Table.Td>
            <Table.Td>
                <TruncatedText 
                    text={appointment.description} 
                    title={`Description - Appointment #${appointment.id}`}
                />
            </Table.Td>
            <Table.Td>{getStatusBadge(appointment)}</Table.Td>
            <Table.Td>
                {appointment.feedback ? 
                    <TruncatedText 
                        text={appointment.feedback} 
                        title={`Feedback - Appointment #${appointment.id}`}
                    /> : 
                    '-'
                }
            </Table.Td>
            <Table.Td>{getTeamDisplay(appointment)}</Table.Td>
            <Table.Td>
                <Group>
                    <ActionIcon
                        color="green"
                        onClick={() => handleApproveAppointment(appointment.id)}
                        title="Approve"
                        disabled={appointment.admitted || appointment.discharged}
                    >
                        <CheckCircleIcon style={iconMStyle}/>
                    </ActionIcon>
                    <ActionIcon
                        color="red"
                        onClick={() => handleRejectAppointment(appointment.id)}
                        title="Reject"
                        disabled={appointment.admitted || appointment.discharged}
                    >
                        <CancelIcon style={iconMStyle}/>
                    </ActionIcon>
                    <ActionIcon
                        color={appointment.approved && appointment.assigned_team !== null && !appointment.admitted && !appointment.discharged ? "blue" : "gray"}
                        onClick={() => {
                            if (appointment.approved && appointment.assigned_team !== null && !appointment.admitted && !appointment.discharged) {
                                handlePatientAdmission(appointment.id);
                            }
                        }}
                        disabled={!appointment.approved || appointment.assigned_team === null || appointment.admitted || appointment.discharged}
                        title={
                            appointment.admitted ? "Already admitted" :
                                appointment.discharged ? "Already discharged" :
                                    !appointment.approved ? "Not approved yet" :
                                        appointment.assigned_team === null ? "No team assigned" :
                                            "Admit Patient"
                        }
                    >
                        <HomePlusIcon style={iconMStyle}/>
                    </ActionIcon>

                </Group>
            </Table.Td>
        </Table.Tr>
    ));

    return (
        <Stack>
            <Group justify="space-between" align="center" style={marginLeftRight}>
                <Text size="1.5em" fw={700}>Appointment Management</Text>
            </Group>

            <Card padding="lg" radius="md" withBorder style={marginTopBottom}>
                <Card.Section withBorder>
                    <Accordion variant="filled" chevronPosition="left" defaultValue="advanced-filter">
                        <Accordion.Item value="advanced-filter">
                            <Accordion.Control>Filter</Accordion.Control>
                            <Accordion.Panel>
                                <AppointmentManageFilter onChange={updateFilter}/>
                            </Accordion.Panel>
                        </Accordion.Item>
                    </Accordion>
                </Card.Section>

                <Card.Section>
                    <ResponsiveTableContainer minWidth={600}>
                        <Table striped highlightOnHover withColumnBorders withTableBorder>
                            <Table.Thead>
                                <Table.Tr>
                                    <Table.Th onClick={() => handleSort("id")}>
                                        ID{" "}
                                        {sortKey === "id" && SORT_SYMBOLS[sortDesc ? "desc" : "asc"]}
                                    </Table.Th>
                                    <Table.Th onClick={() => handleSort("patient_id")}>
                                        Patient ID{" "}
                                        {sortKey === "patient_id" && SORT_SYMBOLS[sortDesc ? "desc" : "asc"]}
                                    </Table.Th>
                                    <Table.Th onClick={() => handleSort("category")}>
                                        Category{" "}
                                        {sortKey === "category" && SORT_SYMBOLS[sortDesc ? "desc" : "asc"]}
                                    </Table.Th>
                                    <Table.Th onClick={() => handleSort("appointment_time")}>
                                        Appointment Time{" "}
                                        {sortKey === "appointment_time" && SORT_SYMBOLS[sortDesc ? "desc" : "asc"]}
                                    </Table.Th>
                                    <Table.Th>
                                        Description
                                    </Table.Th>
                                    <Table.Th onClick={() => handleSort("approved")}>
                                        Status{" "}
                                        {sortKey === "approved" && SORT_SYMBOLS[sortDesc ? "desc" : "asc"]}
                                    </Table.Th>
                                    <Table.Th>
                                        Feedback
                                    </Table.Th>
                                    <Table.Th onClick={() => handleSort("assigned_team")}>
                                        Team{" "}
                                        {sortKey === "assigned_team" && SORT_SYMBOLS[sortDesc ? "desc" : "asc"]}
                                    </Table.Th>
                                    <Table.Th>
                                        Actions
                                    </Table.Th>
                                </Table.Tr>
                            </Table.Thead>
                            <Table.Tbody>{rows}</Table.Tbody>
                        </Table>
                    </ResponsiveTableContainer>

                    <Pagination 
                        withEdges 
                        total={appointmentInfo.total_pages} 
                        value={currPage} 
                        onChange={setCurrPage} 
                        mt="sm"
                        style={{justifyItems: "flex-end", ...marginRightBottom}}
                    />
                </Card.Section>
            </Card>
        </Stack>
    );
} 