import {
  mdiAccountMultiple,
  mdiCog,
  mdiContentCopy,
  mdiCrowd,
  mdiFamilyTree,
  mdiHumanMaleFemale,
  mdiLockCheck,
  mdiPlus,
  mdiRefresh,
} from "@mdi/js";
import Icon from "@mdi/react";
import HomeIcon from "@mui/icons-material/Home";
import {
  Box,
  Divider,
  IconButton,
  List,
  ListItem,
  ListItemButton,
  ListItemIcon,
  ListItemSecondaryAction,
  ListItemText,
  ListSubheader,
  Tooltip,
} from "@mui/material";
import React from "react";
import { Outlet, useLocation, useParams } from "react-router-dom";
import { CoupleApi, CouplesList } from "../api/CoupleApi";
import { ExtendedFamilyInfo, FamilyApi } from "../api/FamilyApi";
import { MemberApi, MembersList } from "../api/MemberApi";
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
import { AsyncWidget } from "./AsyncWidget";
import { RouterLink } from "./RouterLink";

interface FamilyContext {
  family: ExtendedFamilyInfo;
  members: MembersList;
  couples: CouplesList;
  familyId: number;
  reloadFamilyInfo: () => void;
  reloadMembersList: () => Promise<void>;
  reloadCouplesList: () => Promise<void>;
}

const FamilyContextK = React.createContext<FamilyContext | null>(null);

export function BaseFamilyRoute(): React.ReactElement {
  const { familyId } = useParams();
  const snackbar = useSnackbar();
  const alert = useAlert();
  const confirm = useConfirm();

  const [family, setFamily] = React.useState<null | ExtendedFamilyInfo>(null);
  const [members, setMembers] = React.useState<null | MembersList>(null);
  const [couples, setCouples] = React.useState<null | CouplesList>(null);

  const loadKey = React.useRef(1);

  const loadPromise = React.useRef<() => void>();

  const load = async () => {
    const familyID = Number(familyId);
    setFamily(await FamilyApi.GetSingle(familyID));
    setMembers(await MemberApi.GetEntireList(familyID));
    setCouples(await CoupleApi.GetEntireList(familyID));
  };

  const onReload = async () => {
    loadKey.current += 1;
    setFamily(null);
    setMembers(null);
    setCouples(null);

    return new Promise<void>((res, _rej) => {
      loadPromise.current = () => res();
    });
  };

  const copyInvitationCode = async () => {
    navigator.clipboard.writeText(family!.invitation_code);
    snackbar("Le code d'invitation a été copié dans le presse papier !");
  };

  const changeInvitationCode = async () => {
    try {
      if (
        !(await confirm(
          "Voulez-vous vraiment générer un nouveau code d'invitation pour cette famille ? Cette action aura pour effet d'invalider l'ancien code !"
        ))
      )
        return;

      await FamilyApi.RenewInvitationCode(family!.family_id);

      snackbar("Le code d'invitation a été changé avec succès !");

      onReload();
    } catch (e) {
      console.error(e);
      alert("Echec du renouvellement du code d'invitation !");
    }
  };

  return (
    <AsyncWidget
      ready={family !== null && members !== null}
      loadKey={`${familyId}-${loadKey.current}`}
      load={load}
      errMsg="Échec du chargement des informations de la famille !"
      build={() => {
        if (loadPromise.current != null) {
          loadPromise.current?.();
          loadPromise.current = undefined;
        }

        return (
          <FamilyContextK.Provider
            value={{
              family: family!,
              members: members!,
              couples: couples!,
              familyId: family!.family_id,
              reloadFamilyInfo: onReload,
              reloadMembersList: onReload,
              reloadCouplesList: onReload,
            }}
          >
            <Box
              sx={{
                display: "flex",
                flex: "2",
              }}
            >
              <List
                component="nav"
                sx={{
                  minWidth: "280px",
                  backgroundColor: "background.paper",
                }}
              >
                <ListSubheader component="div">
                  Famille <em>{family?.name}</em>
                </ListSubheader>

                <FamilyLink icon={<HomeIcon />} label="Accueil" uri="" />

                <FamilyLink
                  icon={<Icon path={mdiCrowd} size={1} />}
                  label="Membres"
                  uri="members"
                  secondaryAction={
                    <Tooltip title="Créer une nouvelle fiche de membre">
                      <RouterLink to={family!.URL("member/create")}>
                        <IconButton>
                          <Icon path={mdiPlus} size={0.75} />
                        </IconButton>
                      </RouterLink>
                    </Tooltip>
                  }
                />

                <FamilyLink
                  icon={<Icon path={mdiHumanMaleFemale} size={1} />}
                  label="Couples"
                  uri="couples"
                  secondaryAction={
                    <Tooltip title="Créer une nouvelle fiche de couple">
                      <RouterLink to={family!.URL("couple/create")}>
                        <IconButton>
                          <Icon path={mdiPlus} size={0.75} />
                        </IconButton>
                      </RouterLink>
                    </Tooltip>
                  }
                />

                <FamilyLink
                  icon={<Icon path={mdiFamilyTree} size={1} />}
                  label="Arbre"
                  uri="tree"
                />

                <Divider sx={{ my: 1 }} />
                <ListSubheader component="div">Administration</ListSubheader>

                <FamilyLink
                  icon={<Icon path={mdiAccountMultiple} size={1} />}
                  label="Utilisateurs"
                  uri="users"
                />

                <FamilyLink
                  icon={<Icon path={mdiCog} size={1} />}
                  label="Paramètres"
                  uri="settings"
                />

                {/* Invitation code */}

                <ListItem
                  dense
                  secondaryAction={
                    <span>
                      <Tooltip title="Copier le code d'invitation dans le presse papier">
                        <IconButton onClick={copyInvitationCode}>
                          <Icon path={mdiContentCopy} size={0.75} />
                        </IconButton>
                      </Tooltip>

                      {family!.is_admin && (
                        <Tooltip title="Changer le code d'activation">
                          <IconButton onClick={changeInvitationCode}>
                            <Icon path={mdiRefresh} size={0.75} />
                          </IconButton>
                        </Tooltip>
                      )}
                    </span>
                  }
                >
                  <ListItemIcon>
                    <Icon path={mdiLockCheck} size={1} />
                  </ListItemIcon>
                  <ListItemText
                    primary="Code d'invitation"
                    secondary={family?.invitation_code}
                  />
                </ListItem>
              </List>

              <Box
                component="main"
                sx={{
                  flexGrow: 1,
                  overflow: "auto",
                  padding: "20px",
                  display: "flex",
                  flexDirection: "column",
                }}
              >
                <Outlet />
              </Box>
            </Box>
          </FamilyContextK.Provider>
        );
      }}
    />
  );
}

export function useFamily(): FamilyContext {
  return React.useContext(FamilyContextK)!;
}

function FamilyLink(p: {
  icon: React.ReactElement;
  uri: string;
  label: string;
  secondaryAction?: React.ReactElement;
}): React.ReactElement {
  const family = useFamily();
  const location = useLocation();
  const link = family.family.URL(p.uri);

  return (
    <RouterLink to={link}>
      <ListItemButton selected={link === location.pathname}>
        <ListItemIcon>{p.icon}</ListItemIcon>
        <ListItemText primary={p.label} />
        {p.secondaryAction && (
          <ListItemSecondaryAction>{p.secondaryAction}</ListItemSecondaryAction>
        )}
      </ListItemButton>
    </RouterLink>
  );
}
