import type {Route} from "../../../.react-router/types/app/pages/dashboard/+types/Home";
import {useEffect, useState} from "react";
import {useNavigate, useOutletContext} from "react-router";
import {
    type DoctorDataWithPermission,
    type DoctorTeamInfo,
    type OutletContextType,
    type PatientBookingInfo,
    type PatientData,
    type TreatmentInfoWithDoctorInfo,
    type WardInfo
} from "~/utils/models.ts";
import {Badge, Button, Card, Grid, Group, Modal, PasswordInput, Stack, Table, Text} from "@mantine/core";
import {
    apiChangeMyPassword,
    apiGetPatientBookingList,
    apiGetTreatmentRecords,
    apiPatientGetCurrentWard
} from "~/utils/hms_api.ts";
import {showErrorMessage, showInfoMessage} from "~/utils/utils.ts";
import {iconMStyle, marginLeftRight, marginRound, marginTop} from "~/styles.ts";
import {useForm} from "@mantine/form";
import {BookingCategory, DashboardPageType, DoctorGrade, UserType} from "~/utils/hms_enums.ts";
import {confirmEditDoctor, confirmEditPatient} from "~/components/subs/confirms.tsx";
import EditIcon from "mdi-react/EditIcon";
import LockResetIcon from "mdi-react/LockResetIcon";
import ArrowRightIcon from "mdi-react/ArrowRightIcon";
import {TruncatedText} from "~/components/subs/TruncatedText.tsx";
import {PatientInfoDisplay} from "~/components/subs/PatientInfoDisplay.tsx";
import {TeamInfoDisplay} from "~/components/subs/TeamInfoDisplay.tsx";
import {DoctorInfoDisplay} from "~/components/subs/DoctorInfoDisplay.tsx";
import DoctorTeamsSimple from "~/components/subs/DoctorTeamsSimple.tsx";
import { ResponsiveTableContainer } from "~/components/subs/ResponsiveTableContainer";

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

interface ChangePasswordModalProps {
    opened: boolean;
    onClose: () => void;
    onSuccess: () => void;
}

function ChangePasswordModal({ opened, onClose, onSuccess }: ChangePasswordModalProps) {
    const form = useForm({
        initialValues: {
            old_password: '',
            new_password: '',
            confirm_password: '',
        },
        validate: {
            old_password: (value) => (!value ? 'Current password is required' : null),
            new_password: (value) => (!value ? 'New password is required' : value.length < 6 ? 'Password must be at least 6 characters' : null),
            confirm_password: (value, values) => (value !== values.new_password ? 'Passwords do not match' : null),
        },
    });

    const handleSubmit = (values: typeof form.values) => {
        apiChangeMyPassword(values.old_password, values.new_password)
            .then(res => {
                if (res.success) {
                    showInfoMessage('', 'Password changed successfully', 3000);
                    form.reset();
                    onClose();
                    onSuccess();
                } else {
                    showErrorMessage(res.message, 'Failed to change password');
                }
            })
            .catch(err => {
                showErrorMessage(err.toString(), 'Failed to change password');
            });
    };

    return (
        <Modal opened={opened} onClose={onClose} title="Change Password" centered>
            <form onSubmit={form.onSubmit(handleSubmit)}>
                <Stack>
                    <PasswordInput
                        label="Current Password"
                        placeholder="Enter your current password"
                        withAsterisk
                        {...form.getInputProps('old_password')}
                    />
                    <PasswordInput
                        label="New Password"
                        placeholder="Enter new password"
                        withAsterisk
                        {...form.getInputProps('new_password')}
                    />
                    <PasswordInput
                        label="Confirm New Password"
                        placeholder="Confirm new password"
                        withAsterisk
                        {...form.getInputProps('confirm_password')}
                    />
                    <Group justify="flex-end" mt="md">
                        <Button variant="outline" onClick={onClose}>Cancel</Button>
                        <Button type="submit">Change Password</Button>
                    </Group>
                </Stack>
            </form>
        </Modal>
    );
}

interface PatientHomeProps {
    patientData: PatientData;
    refreshUserInfo: () => void;
}

function PatientHome({ patientData, refreshUserInfo }: PatientHomeProps) {
    const navigate = useNavigate();
    const [changePasswordOpened, setChangePasswordOpened] = useState(false);
    const [currentWard, setCurrentWard] = useState<WardInfo | null>(null);
    const [loadingWard, setLoadingWard] = useState(false);
    const [bookings, setBookings] = useState<PatientBookingInfo[]>([]);
    const [loadingBookings, setLoadingBookings] = useState(false);
    const [treatments, setTreatments] = useState<TreatmentInfoWithDoctorInfo[]>([]);
    const [loadingTreatments, setLoadingTreatments] = useState(false);
    const { changePage } = useOutletContext<OutletContextType>();

    useEffect(() => {
        fetchCurrentWard();
        fetchRecentBookings();
        fetchRecentTreatments();
    }, []);

    const fetchCurrentWard = () => {
        setLoadingWard(true);
        apiPatientGetCurrentWard()
            .then(res => {
                if (res.success && res.data.ward) {
                    setCurrentWard(res.data.ward);
                } else {
                    setCurrentWard(null);
                }
            })
            .catch(err => {
                showErrorMessage(err.toString(), 'Error');
            })
            .finally(() => {
                setLoadingWard(false);
            });
    };

    const fetchRecentBookings = () => {
        setLoadingBookings(true);
        apiGetPatientBookingList(1)
            .then(res => {
                if (res.success) {
                    const recentBookings = [...res.data.appointments]
                        .sort((a, b) => b.id - a.id)
                        .slice(0, 5);
                    setBookings(recentBookings);
                } else {
                    showErrorMessage(res.message, 'Failed to load appointments');
                }
            })
            .catch(err => {
                showErrorMessage(err.toString(), 'Error');
            })
            .finally(() => {
                setLoadingBookings(false);
            });
    };

    const fetchRecentTreatments = () => {
        setLoadingTreatments(true);
        apiGetTreatmentRecords(1, patientData.id, null, null)
            .then(res => {
                if (res.success) {
                    // Get only the 10 most recent treatments
                    const recentTreatments = [...res.data.treatments]
                        .sort((a, b) => b.treated_at - a.treated_at)
                        .slice(0, 10);
                    setTreatments(recentTreatments);
                } else {
                    showErrorMessage(res.message, 'Failed to load treatments');
                }
            })
            .catch(err => {
                showErrorMessage(err.toString(), 'Error');
            })
            .finally(() => {
                setLoadingTreatments(false);
            });
    };

    const handleEditInfo = () => {
        confirmEditPatient(patientData, () => {
            refreshUserInfo();
        });
    };

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

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

    const bookingRows = bookings.map((booking) => (
        <Table.Tr key={booking.id}>
            <Table.Td>{booking.id}</Table.Td>
            <Table.Td>{getCategoryDisplay(booking.category)}</Table.Td>
            <Table.Td>{new Date(booking.appointment_time * 1000).toLocaleString('en-GB').replace(',', '')}</Table.Td>
            <Table.Td>
                <TruncatedText 
                    text={booking.description} 
                    title={`Description - Appointment #${booking.id}`}
                />
            </Table.Td>
            <Table.Td>{getStatusBadge(booking)}</Table.Td>
            <Table.Td>
                {booking.assigned_team ? (
                    <TeamInfoDisplay teamId={booking.assigned_team} />
                ) : (
                    <Text size="sm" c="dimmed">Not Assigned</Text>
                )}
            </Table.Td>
            <Table.Td>
                {booking.feedback ? (
                    <TruncatedText 
                        text={booking.feedback} 
                        title={`Feedback - Appointment #${booking.id}`}
                    />
                ) : (
                    <Text>-</Text>
                )}
            </Table.Td>
        </Table.Tr>
    ));

    const treatmentRows = treatments.map((treatment) => (
        <Table.Tr key={treatment.id}>
            <Table.Td>{treatment.id}</Table.Td>
            <Table.Td>
                <DoctorInfoDisplay doctorId={treatment.doctor_id} />
            </Table.Td>
            <Table.Td>
                {treatment.team ? (
                    <TeamInfoDisplay teamId={treatment.team.id} />
                ) : (
                    <Text size="sm" c="dimmed">Not Assigned</Text>
                )}
            </Table.Td>
            <Table.Td>
                <TruncatedText 
                    text={treatment.treat_info} 
                    title={`Treatment Info - Record #${treatment.id}`}
                />
            </Table.Td>
            <Table.Td>{new Date(treatment.treated_at * 1000).toLocaleString('en-GB').replace(',', '')}</Table.Td>
        </Table.Tr>
    ));

    return (
        <Stack>
            <Card padding="lg" radius="md" withBorder>
                <Card.Section withBorder>
                    <Group justify="space-between" style={marginRound}>
                        <Stack gap="xs">
                            <Text size="xl" fw={700}>Hi, {patientData.title} {patientData.name}</Text>
                            <Text size="sm" c="dimmed">Welcome to the Hospital Management System</Text>
                        </Stack>
                        <Group>
                            <Button
                                leftSection={<EditIcon style={iconMStyle} />}
                                onClick={handleEditInfo}
                            >
                                Edit Profile
                            </Button>
                            <Button
                                leftSection={<LockResetIcon style={iconMStyle} />}
                                onClick={() => setChangePasswordOpened(true)}
                            >
                                Change Password
                            </Button>
                        </Group>
                    </Group>
                </Card.Section>
                
                <Card.Section>
                    <Grid style={marginRound}>
                        <Grid.Col span={{ base: 12, md: 6 }}>
                            <Stack gap="sm">
                                <Group>
                                    <Text fw={500} w={100}>Full Name:</Text>
                                    <Text>{patientData.title} {patientData.name}</Text>
                                </Group>
                                <Group>
                                    <Text fw={500} w={100}>Gender:</Text>
                                    <Text>{patientData.gender}</Text>
                                </Group>
                                <Group>
                                    <Text fw={500} w={100}>Birth Date:</Text>
                                    <Text>{patientData.birth_date}</Text>
                                </Group>
                            </Stack>
                        </Grid.Col>
                        <Grid.Col span={{ base: 12, md: 6 }}>
                            <Stack gap="sm">
                                <Group>
                                    <Text fw={500} w={100}>Email:</Text>
                                    <Text>{patientData.email}</Text>
                                </Group>
                                <Group>
                                    <Text fw={500} w={100}>Phone:</Text>
                                    <Text>{patientData.phone}</Text>
                                </Group>
                                <Group>
                                    <Text fw={500} w={100}>Address:</Text>
                                    <Text>{patientData.address}, {patientData.postcode}</Text>
                                </Group>
                            </Stack>
                        </Grid.Col>
                    </Grid>
                </Card.Section>
            </Card>

            <Card padding="lg" radius="md" withBorder>
                <Card.Section withBorder>
                    <Group style={{...marginLeftRight, ...marginTop}}>
                        <Text size="lg" fw={700} mb="md">Current Ward</Text>
                    </Group>
                </Card.Section>

                <Card.Section>
                    {loadingWard ? (
                        <Group style={marginRound}>
                            <Text>Loading...</Text>
                        </Group>
                    ) : currentWard ? (
                        <Grid style={marginRound}>
                            <Grid.Col span={6}>
                                <Stack gap="sm">
                                    <Group>
                                        <Text fw={500} w={120}>Ward ID:</Text>
                                        <Text>{currentWard.id}</Text>
                                    </Group>
                                    <Group>
                                        <Text fw={500} w={120}>Ward Name:</Text>
                                        <Text>{currentWard.name}</Text>
                                    </Group>
                                </Stack>
                            </Grid.Col>
                            <Grid.Col span={6}>
                                <Stack gap="sm">
                                    <Group>
                                        <Text fw={500} w={120}>Ward Type:</Text>
                                        <Text>{currentWard.type.replace(/_/g, ' ')}</Text>
                                    </Group>
                                    <Group>
                                        <Text fw={500} w={120}>Occupancy:</Text>
                                        <Text>{currentWard.current_occupancy} / {currentWard.total_capacity}</Text>
                                    </Group>
                                </Stack>
                            </Grid.Col>
                        </Grid>
                    ) : (
                        <Group style={marginRound}>
                            <Text c="dimmed">You are not currently admitted to any ward.</Text>
                        </Group>
                    )}
                </Card.Section>
            </Card>

            <Card padding="lg" radius="md" withBorder>
                <Group justify="space-between" mb="md">
                    <Text size="lg" fw={700}>Recent Appointments</Text>
                    <Button 
                        rightSection={<ArrowRightIcon style={iconMStyle} />}
                        variant="subtle"
                        onClick={() => changePage(DashboardPageType.PatientBooking)}
                    >
                        View All
                    </Button>
                </Group>
                
                <Card.Section withBorder>
                    <Group style={marginRound}>
                        {loadingBookings ? (
                            <Text>Loading...</Text>
                        ) : bookings.length > 0 ? (
                            <ResponsiveTableContainer minWidth={600}>
                                <Table striped highlightOnHover withColumnBorders withTableBorder>
                                    <Table.Thead>
                                        <Table.Tr>
                                            <Table.Th>ID</Table.Th>
                                            <Table.Th>Category</Table.Th>
                                            <Table.Th>Appointment Time</Table.Th>
                                            <Table.Th>Description</Table.Th>
                                            <Table.Th>Status</Table.Th>
                                            <Table.Th>Team</Table.Th>
                                            <Table.Th>Feedback</Table.Th>
                                        </Table.Tr>
                                    </Table.Thead>
                                    <Table.Tbody>{bookingRows}</Table.Tbody>
                                </Table>
                            </ResponsiveTableContainer>
                        ) : (
                            <Text c="dimmed">No appointments found.</Text>
                        )}
                    </Group>
                </Card.Section>
            </Card>

            <Card padding="lg" radius="md" withBorder>
                <Group justify="space-between" mb="md">
                    <Text size="lg" fw={700}>Recent Treatments</Text>
                    <Button 
                        rightSection={<ArrowRightIcon style={iconMStyle} />}
                        variant="subtle"
                        onClick={() => changePage(DashboardPageType.TreatmentRecord, `/dashboard/treatment_record/${patientData.id}`)}
                    >
                        View All
                    </Button>
                </Group>
                
                <Card.Section withBorder>
                    <Group style={marginRound}>
                        {loadingTreatments ? (
                            <Text>Loading...</Text>
                        ) : treatments.length > 0 ? (
                            <ResponsiveTableContainer minWidth={600}>
                                <Table striped highlightOnHover withColumnBorders withTableBorder>
                                    <Table.Thead>
                                        <Table.Tr>
                                            <Table.Th>ID</Table.Th>
                                            <Table.Th>Doctor</Table.Th>
                                            <Table.Th>Medical Team</Table.Th>
                                            <Table.Th>Treatment Info</Table.Th>
                                            <Table.Th>Treatment Date</Table.Th>
                                        </Table.Tr>
                                    </Table.Thead>
                                    <Table.Tbody>{treatmentRows}</Table.Tbody>
                                </Table>
                            </ResponsiveTableContainer>
                        ) : (
                            <Text c="dimmed">No treatment records found.</Text>
                        )}
                    </Group>
                </Card.Section>
            </Card>

            <ChangePasswordModal 
                opened={changePasswordOpened} 
                onClose={() => setChangePasswordOpened(false)} 
                onSuccess={() => {navigate("/dashboard/account/login")}}
            />
        </Stack>
    );
}

interface DoctorHomeProps {
    doctorData: DoctorDataWithPermission;
    doctorTeams: DoctorTeamInfo[];
    refreshUserInfo: () => void;
}

function DoctorHome({ doctorData, doctorTeams, refreshUserInfo }: DoctorHomeProps) {
    const [changePasswordOpened, setChangePasswordOpened] = useState(false);
    const [assignedPatients, setAssignedPatients] = useState<any[]>([]);
    const [loadingPatients, setLoadingPatients] = useState(false);
    const { changePage } = useOutletContext<OutletContextType>();
    const navigate = useNavigate();

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

    const fetchAssignedPatients = () => {
        setLoadingPatients(true);
        apiGetTreatmentRecords(1, null, doctorData.id, null)
            .then(res => {
                if (res.success) {
                    const uniquePatientIds = new Set();
                    const patientTreatments = res.data.treatments
                        .filter(treatment => {
                            if (!uniquePatientIds.has(treatment.patient_id)) {
                                uniquePatientIds.add(treatment.patient_id);
                                return true;
                            }
                            return false;
                        })
                        .slice(0, 15); // Get only the first 15 unique patients
                    
                    setAssignedPatients(patientTreatments);
                } else {
                    showErrorMessage(res.message, 'Failed to load patient assignments');
                }
            })
            .catch(err => {
                showErrorMessage(err.toString(), 'Error');
            })
            .finally(() => {
                setLoadingPatients(false);
            });
    };

    const handleEditInfo = () => {
        confirmEditDoctor(doctorData, () => {
            refreshUserInfo();
        });
    };

    const patientRows = assignedPatients.map((treatment) => (
        <Table.Tr key={treatment.id}>
            <Table.Td>
                <PatientInfoDisplay patientId={treatment.patient_id} />
            </Table.Td>
            <Table.Td>
                <TruncatedText 
                    text={treatment.treat_info} 
                    title={`Treatment Info - Record #${treatment.id}`}
                />
            </Table.Td>
            <Table.Td>{new Date(treatment.treated_at * 1000).toLocaleString('en-GB').replace(',', '')}</Table.Td>
        </Table.Tr>
    ));

    return (
        <Stack>
            <Card padding="lg" radius="md" withBorder>
                <Card.Section withBorder>
                    <Group justify="space-between" style={marginRound}>
                        <Stack gap="xs">
                            <Text size="xl" fw={700}>Hi, {doctorData.title} {doctorData.name}</Text>
                            <Text size="sm" c="dimmed">Welcome to the Hospital Management System</Text>
                        </Stack>
                        <Group>
                            <Button
                                leftSection={<EditIcon style={iconMStyle} />}
                                onClick={handleEditInfo}
                            >
                                Edit Profile
                            </Button>
                            <Button
                                leftSection={<LockResetIcon style={iconMStyle} />}
                                onClick={() => setChangePasswordOpened(true)}
                            >
                                Change Password
                            </Button>
                        </Group>
                    </Group>
                </Card.Section>

                <Card.Section>
                    <Grid style={marginRound}>
                        <Grid.Col span={{ base: 12, md: 6 }}>
                            <Stack gap="sm">
                                <Group>
                                    <Text fw={500} w={100}>Full Name:</Text>
                                    <Text>{doctorData.title} {doctorData.name}</Text>
                                </Group>
                                <Group>
                                    <Text fw={500} w={100}>Grade:</Text>
                                    <Text>{DoctorGrade[doctorData.grade]}</Text>
                                </Group>
                                <Group>
                                    <Text fw={500} w={100}>Gender:</Text>
                                    <Text>{doctorData.gender}</Text>
                                </Group>
                            </Stack>
                        </Grid.Col>
                        <Grid.Col span={{ base: 12, md: 6 }}>
                            <Stack gap="sm">
                                <Group>
                                    <Text fw={500} w={100}>Birth Date:</Text>
                                    <Text>{doctorData.birth_date}</Text>
                                </Group>
                                <Group>
                                    <Text fw={500} w={100}>Email:</Text>
                                    <Text>{doctorData.email}</Text>
                                </Group>
                                <Group>
                                    <Text fw={500} w={100}>Phone:</Text>
                                    <Text>{doctorData.phone}</Text>
                                </Group>
                            </Stack>
                        </Grid.Col>
                    </Grid>
                </Card.Section>
            </Card>

            <DoctorTeamsSimple doctorTeams={doctorTeams} />

            <Card padding="lg" radius="md" withBorder>
                <Group justify="space-between" mb="md">
                    <Text size="lg" fw={700}>Recent Patients</Text>
                    <Button 
                        rightSection={<ArrowRightIcon style={iconMStyle} />}
                        variant="subtle"
                        onClick={() => changePage(DashboardPageType.DoctorTreatment)}
                    >
                        View All
                    </Button>
                </Group>
                
                <Card.Section withBorder>
                    <Group style={marginRound}>
                        {loadingPatients ? (
                            <Text>Loading...</Text>
                        ) : assignedPatients.length > 0 ? (
                            <ResponsiveTableContainer minWidth={600}>
                                <Table striped highlightOnHover withColumnBorders withTableBorder>
                                    <Table.Thead>
                                        <Table.Tr>
                                            <Table.Th>Patient</Table.Th>
                                            <Table.Th>Last Treatment</Table.Th>
                                            <Table.Th>Treatment Date</Table.Th>
                                        </Table.Tr>
                                    </Table.Thead>
                                    <Table.Tbody>{patientRows}</Table.Tbody>
                                </Table>
                            </ResponsiveTableContainer>
                        ) : (
                            <Text c="dimmed">No patients assigned yet.</Text>
                        )}
                    </Group>
                </Card.Section>
            </Card>

            <ChangePasswordModal 
                opened={changePasswordOpened} 
                onClose={() => setChangePasswordOpened(false)} 
                onSuccess={() => {navigate("/dashboard/account/login")}}
            />
        </Stack>
    );
}

export default function Component() {
    const { loginUserInfo, refreshMyInfo } = useOutletContext<OutletContextType>();

    if (!loginUserInfo) {
        return (
            <Stack>
                <Text size="1.5em" fw={700} style={marginLeftRight}>Dashboard</Text>
                <Text>Loading user information...</Text>
            </Stack>
        );
    }

    const isDoctor = loginUserInfo.user_type === UserType.DOCTOR;
    
    return (
        <Stack>
            {isDoctor && loginUserInfo.doctor_data ? (
                <DoctorHome 
                    doctorData={loginUserInfo.doctor_data}
                    doctorTeams={loginUserInfo.doctor_teams || []} 
                    refreshUserInfo={refreshMyInfo} 
                />
            ) : loginUserInfo.patient_data ? (
                <PatientHome 
                    patientData={loginUserInfo.patient_data}
                    refreshUserInfo={refreshMyInfo} 
                />
            ) : (
                <Text>Unable to load user profile information.</Text>
            )}
        </Stack>
    );
}
