import ClearIcon from "@mui/icons-material/Clear";
import DeleteIcon from "@mui/icons-material/Delete";
import EditIcon from "@mui/icons-material/Edit";
import FileDownloadIcon from "@mui/icons-material/FileDownload";
import SaveIcon from "@mui/icons-material/Save";
import { Button, Stack } from "@mui/material";
import Grid from "@mui/material/Grid2";
import React from "react";
import { useNavigate, useParams } from "react-router-dom";
import { ServerApi } from "../../../api/ServerApi";
import { Couple, CoupleApi } from "../../../api/genealogy/CoupleApi";
import { Member } from "../../../api/genealogy/MemberApi";
import { useAlert } from "../../../hooks/context_providers/AlertDialogProvider";
import { useConfirm } from "../../../hooks/context_providers/ConfirmDialogProvider";
import { useLoadingMessage } from "../../../hooks/context_providers/LoadingMessageProvider";
import { useSnackbar } from "../../../hooks/context_providers/SnackbarProvider";
import { useQuery } from "../../../hooks/useQuery";
import { AsyncWidget } from "../../../widgets/AsyncWidget";
import { useFamily } from "../../../widgets/BaseFamilyRoute";
import { ConfirmLeaveWithoutSaveDialog } from "../../../widgets/ConfirmLeaveWithoutSaveDialog";
import { CouplePhoto } from "../../../widgets/CouplePhoto";
import { FamilyPageTitle } from "../../../widgets/FamilyPageTitle";
import { MemberItem } from "../../../widgets/MemberItem";
import { PropertiesBox } from "../../../widgets/PropertiesBox";
import { RouterLink } from "../../../widgets/RouterLink";
import { DateInput } from "../../../widgets/forms/DateInput";
import { MemberInput } from "../../../widgets/forms/MemberInput";
import { PropSelect } from "../../../widgets/forms/PropSelect";
import { UploadPhotoButton } from "../../../widgets/forms/UploadPhotoButton";
import { useGenealogy } from "../../../widgets/genealogy/BaseGenealogyRoute";

/**
 * Create a new couple route
 */
export function FamilyCreateCoupleRoute(): React.ReactElement {
  const alert = useAlert();
  const snackbar = useSnackbar();

  const [shouldQuit, setShouldQuit] = React.useState(false);
  const n = useNavigate();
  const genealogy = useGenealogy();
  const family = useFamily();

  const params = useQuery();
  const couple = Couple.New(family.family.family_id);
  const wife = Number(params.get("wife"));
  const husband = Number(params.get("husband"));
  if (wife) couple.wife = wife;
  if (husband) couple.husband = husband;

  const create = async (m: Couple) => {
    try {
      const r = await CoupleApi.Create(m);

      await genealogy.reloadCouplesList();

      setShouldQuit(true);
      n(family.family.coupleURL(r));
      snackbar(`La fiche pour le couple a été créée avec succès !`);
    } catch (e) {
      console.error(e);
      alert("Echec de la création du couple !");
    }
  };

  const cancel = () => {
    setShouldQuit(true);
    n(family.family.URL("genealogy/couples"));
  };

  return (
    <CouplePage
      couple={couple}
      creating={true}
      editing={true}
      onCancel={cancel}
      onSave={create}
      shouldAllowLeaving={shouldQuit}
    />
  );
}

/**
 * Get existing couple route
 */
export function FamilyCoupleRoute(): React.ReactElement {
  const count = React.useRef(1);

  const n = useNavigate();
  const alert = useAlert();
  const confirm = useConfirm();
  const snackbar = useSnackbar();

  const family = useFamily();
  const genealogy = useGenealogy();
  const { coupleId } = useParams();

  const [couple, setCouple] = React.useState<Couple>();
  const load = async () => {
    setCouple(await CoupleApi.GetSingle(family.familyId, Number(coupleId)));
  };

  const forceReload = async () => {
    count.current += 1;
    setCouple(undefined);

    await genealogy.reloadCouplesList();
  };

  const deleteCouple = async () => {
    try {
      if (
        !(await confirm(
          "Voulez-vous vraiment supprimer cette fiche de couple ? L'opération n'est pas réversible !"
        ))
      )
        return;

      await CoupleApi.Delete(couple!);

      snackbar("La fiche du couple a été supprimée avec succès !");
      n(family.family.URL("genealogy/couples"));

      await genealogy.reloadCouplesList();
    } catch (e) {
      console.error(e);
      alert("Échec de la suppression du couple !");
    }
  };

  return (
    <AsyncWidget
      loadKey={`${coupleId}-${count.current}`}
      load={load}
      ready={couple !== undefined}
      errMsg="Echec du chargement des informations du couple !"
      build={() => (
        <CouplePage
          couple={couple!}
          children={genealogy.members.childrenOfCouple(couple!)}
          creating={false}
          editing={false}
          onRequestDelete={deleteCouple}
          onRequestEdit={() => n(family.family.coupleURL(couple!, true))}
          onForceReload={forceReload}
        />
      )}
    />
  );
}

/**
 * Edit existing couple route
 */
export function FamilyEditCoupleRoute(): React.ReactElement {
  const n = useNavigate();
  const { coupleId } = useParams();

  const alert = useAlert();
  const snackbar = useSnackbar();

  const [shouldQuit, setShouldQuit] = React.useState(false);

  const genealogy = useGenealogy();
  const family = useFamily();

  const [couple, setCouple] = React.useState<Couple>();
  const load = async () => {
    setCouple(await CoupleApi.GetSingle(family.familyId, Number(coupleId)));
  };

  const cancel = () => {
    setShouldQuit(true);
    n(family.family.coupleURL(couple!));
    //n(-1);
  };

  const save = async (c: Couple) => {
    try {
      await CoupleApi.Update(c);

      snackbar("Les informations du couple ont été mises à jour avec succès !");

      await genealogy.reloadCouplesList();

      setShouldQuit(true);
      n(family.family.coupleURL(c, false));
    } catch (e) {
      console.error(e);
      alert("Échec de la mise à jour des informations du couple !");
    }
  };

  return (
    <AsyncWidget
      loadKey={coupleId}
      load={load}
      errMsg="Échec du chargement des informations du couple !"
      build={() => (
        <CouplePage
          couple={couple!}
          creating={false}
          editing={true}
          onCancel={cancel}
          onSave={save}
          shouldAllowLeaving={shouldQuit}
        />
      )}
    />
  );
}

export function CouplePage(p: {
  couple: Couple;
  editing: boolean;
  creating: boolean;
  shouldAllowLeaving?: boolean;
  children?: Member[];
  onCancel?: () => void;
  onSave?: (m: Couple) => Promise<void>;
  onRequestEdit?: () => void;
  onRequestDelete?: () => void;
  onForceReload?: () => void;
}): React.ReactElement {
  const confirm = useConfirm();
  const snackbar = useSnackbar();
  const loadingMessage = useLoadingMessage();

  const family = useFamily();

  const [changed, setChanged] = React.useState(false);
  const [couple, setCouple] = React.useState(
    new Couple(structuredClone(p.couple))
  );

  const updatedCouple = () => {
    setChanged(true);
    setCouple(new Couple(structuredClone(couple)));
  };

  const save = async () => {
    loadingMessage.show(
      "Enregistrement des informations du couple en cours..."
    );
    await p.onSave!(couple);
    loadingMessage.hide();
  };

  const cancel = async () => {
    if (
      changed &&
      !(await confirm(
        "Voulez-vous vraiment retirer les modifications apportées ? Celles-ci seront perdues !"
      ))
    )
      return;

    p.onCancel!();
  };

  const uploadNewPhoto = async (b: Blob) => {
    await CoupleApi.SetCouplePhoto(couple, b);
    snackbar("La photo du couple a été mise à jour avec succès !");
    p.onForceReload?.();
  };

  const deletePhoto = async () => {
    try {
      if (!(await confirm("Voulez-vous supprimer cette photo ?"))) return;

      await CoupleApi.RemoveCouplePhoto(couple);

      snackbar("La photo du couple a été supprimée avec succès !");
      p.onForceReload?.();
    } catch (e) {
      console.error(e);
      alert("Échec de la suppresion de la photo !");
    }
  };

  return (
    <div style={{ maxWidth: "2000px", margin: "auto" }}>
      <ConfirmLeaveWithoutSaveDialog
        shouldBlock={changed && p.shouldAllowLeaving !== true}
      />
      <div
        style={{
          display: "flex",
          justifyContent: "space-between",
          alignItems: "center",
        }}
      >
        <FamilyPageTitle
          title={
            (p.editing
              ? p.creating
                ? "Création"
                : "Édition"
              : "Visualisation") + " d'une fiche de couple"
          }
        />
        <Stack direction="row" spacing={1}>
          {/* Edit button */}
          {p.onRequestEdit && (
            <Button
              variant="outlined"
              startIcon={<EditIcon />}
              onClick={p.onRequestEdit}
              size="large"
            >
              Editer
            </Button>
          )}

          {/* Delete button */}
          {p.onRequestDelete && (
            <Button
              variant="outlined"
              startIcon={<DeleteIcon />}
              onClick={p.onRequestDelete}
              size="large"
              color="error"
            >
              Supprimer
            </Button>
          )}

          {/* Save button */}
          {p.editing && changed && (
            <Button
              variant={"contained"}
              startIcon={<SaveIcon />}
              onClick={save}
              size="large"
            >
              Enregistrer
            </Button>
          )}

          {/* Cancel button */}
          {p.editing && (
            <Button
              variant="outlined"
              startIcon={<ClearIcon />}
              onClick={cancel}
              size="small"
            >
              Annuler les modifications
            </Button>
          )}
        </Stack>
      </div>

      <Grid container spacing={2}>
        {/* General info */}
        <Grid size={{ sm: 12, md: 6 }}>
          <PropertiesBox title="Informations générales">
            {/* Husband */}
            <br />
            <MemberInput
              editable={p.editing}
              label="Époux"
              onValueChange={(m) => {
                couple.husband = m;
                updatedCouple();
              }}
              filter={(m) => m.sex === "M" || m.sex === undefined}
              current={couple.husband}
            />

            {/* Wife */}
            <br />
            <MemberInput
              editable={p.editing}
              label="Épouse"
              onValueChange={(m) => {
                couple.wife = m;
                updatedCouple();
              }}
              filter={(m) => m.sex === "F" || m.sex === undefined}
              current={couple.wife}
            />
            <br />

            {/* State */}
            <PropSelect
              editing={p.editing}
              label="Status"
              value={couple.state}
              onValueChange={(s) => {
                couple.state = s;
                updatedCouple();
              }}
              options={ServerApi.Config.couples_states.map((s) => {
                return { label: s.fr, value: s.code };
              })}
            />

            {/* Wedding day */}
            <DateInput
              label="Date du mariage"
              editable={p.editing}
              id="dow"
              value={couple.dateOfWedding}
              onValueChange={(d) => {
                couple.wedding_year = d.year;
                couple.wedding_month = d.month;
                couple.wedding_day = d.day;
                updatedCouple();
              }}
            />

            {/* Divorce day */}
            <DateInput
              label="Date du divorce"
              editable={p.editing}
              id="dod"
              value={couple.dateOfDivorce}
              onValueChange={(d) => {
                couple.divorce_year = d.year;
                couple.divorce_month = d.month;
                couple.divorce_day = d.day;
                updatedCouple();
              }}
            />
          </PropertiesBox>
        </Grid>

        {
          /* Photo */ !family.family.disable_couple_photos && (
            <Grid size={{ sm: 12, md: 6 }}>
              <PropertiesBox title="Photo">
                <div style={{ textAlign: "center" }}>
                  <CouplePhoto couple={couple} width={150} />
                  <br />
                  {p.editing ? (
                    <p>
                      Veuillez enregistrer / annuler les modifications apportées
                      à la fiche avant de changer la photo du couple.
                    </p>
                  ) : (
                    <>
                      <UploadPhotoButton
                        label={couple.hasPhoto ? "Remplacer" : "Ajouter"}
                        onPhotoSelected={uploadNewPhoto}
                        aspect={5 / 4}
                      />{" "}
                      {couple.hasPhoto && (
                        <RouterLink to={couple.photoURL!} target="_blank">
                          <Button
                            variant="outlined"
                            startIcon={<FileDownloadIcon />}
                          >
                            Télécharger
                          </Button>
                        </RouterLink>
                      )}{" "}
                      {couple.hasPhoto && (
                        <Button
                          variant="outlined"
                          startIcon={<DeleteIcon />}
                          color="error"
                          onClick={deletePhoto}
                        >
                          Supprimer
                        </Button>
                      )}
                    </>
                  )}{" "}
                </div>
              </PropertiesBox>
            </Grid>
          )
        }

        {/* Children */}
        {p.children && (
          <Grid size={{ sm: 12, md: 6 }}>
            <PropertiesBox title="Enfants">
              {p.children.length === 0 ? (
                <>Aucun enfant</>
              ) : (
                p.children.map((c) => (
                  <RouterLink key={c.id} to={family.family.memberURL(c)}>
                    <MemberItem member={c} />
                  </RouterLink>
                ))
              )}

              {couple.wife && couple.husband && (
                <div style={{ display: "flex", justifyContent: "end" }}>
                  <RouterLink
                    to={family.family.URL(
                      `genealogy/member/create?mother=${couple.wife}&father=${couple.husband}`
                    )}
                  >
                    <Button>Nouveau</Button>
                  </RouterLink>
                </div>
              )}
            </PropertiesBox>
          </Grid>
        )}
      </Grid>
    </div>
  );
}
