import AddIcon from "@mui/icons-material/Add";
import CheckIcon from "@mui/icons-material/Check";
import CloseIcon from "@mui/icons-material/Close";
import HouseIcon from "@mui/icons-material/House";
import {
  Alert,
  Button,
  Card,
  CardActions,
  CardContent,
  Typography,
} from "@mui/material";
import React from "react";
import {
  Accommodation,
  AccommodationListApi,
} from "../../../api/accommodations/AccommodationListApi";
import {
  AccommodationCalendarURL,
  AccommodationsCalendarURLApi,
} from "../../../api/accommodations/AccommodationsCalendarURLApi";
import { useConfirm } from "../../../hooks/context_providers/ConfirmDialogProvider";
import { useLoadingMessage } from "../../../hooks/context_providers/LoadingMessageProvider";
import { useSnackbar } from "../../../hooks/context_providers/SnackbarProvider";
import { useCreateAccommodationCalendarURL } from "../../../hooks/context_providers/accommodations/CreateAccommodationCalendarURLDialogProvider";
import { useInstallCalendarDialog } from "../../../hooks/context_providers/accommodations/InstallCalendarDialogProvider";
import { useUpdateAccommodation } from "../../../hooks/context_providers/accommodations/UpdateAccommodationDialogProvider";
import { AsyncWidget } from "../../../widgets/AsyncWidget";
import { useFamily } from "../../../widgets/BaseFamilyRoute";
import { FamilyCard } from "../../../widgets/FamilyCard";
import { TimeWidget } from "../../../widgets/TimeWidget";
import { useAccommodations } from "../../../widgets/accommodations/BaseAccommodationsRoute";

const CARDS_WIDTH = "500px";

export function AccommodationsSettingsRoute(): React.ReactElement {
  return (
    <>
      <AccommodationsListCard />
      <AccommodationsCalURLsCard />
    </>
  );
}

function AccommodationsListCard(): React.ReactElement {
  const loading = useLoadingMessage();
  const confirm = useConfirm();
  const snackbar = useSnackbar();

  const family = useFamily();
  const accommodations = useAccommodations();

  const [error, setError] = React.useState<string>();
  const [success, setSuccess] = React.useState<string>();

  const updateAccommodation = useUpdateAccommodation();

  const createAccommodation = async () => {
    setError(undefined);
    setSuccess(undefined);
    try {
      const accommodation = await updateAccommodation(
        {
          name: "",
          open_to_reservations: true,
          need_validation: false,
          color: "2196f3",
        },
        true
      );

      if (!accommodation) return;

      loading.show("Création du logement en cours...");

      await AccommodationListApi.Create(family.family, accommodation);

      snackbar("Le logement a été créé avec succès !");
      await accommodations.reloadAccommodationsList();
    } catch (e) {
      console.error("Failed to create accommodation!", e);
      setError(`Échec de la création du logement! ${e}`);
    } finally {
      loading.hide();
    }
  };

  const requestUpdateAccommodation = async (a: Accommodation) => {
    setError(undefined);
    setSuccess(undefined);
    try {
      const update = await updateAccommodation(a, false);
      if (!update) return;

      loading.show("Mise à jour du logement en cours...");

      await AccommodationListApi.Update(a, update);

      snackbar("Le logement a été créé avec succès !");
      await accommodations.reloadAccommodationsList();
    } catch (e) {
      console.error("Failed to update accommodation!", e);
      setError(`Échec de la mise à jour du logement! ${e}`);
    } finally {
      loading.hide();
    }
  };

  const deleteAccommodation = async (a: Accommodation) => {
    setError(undefined);
    setSuccess(undefined);
    try {
      if (
        !(await confirm(
          `Voulez-vous vraiment supprimer le logement '${a.name}' ? Cette opération est définitive !`
        ))
      )
        return;
      loading.show("Suppression du logement en cours...");

      await AccommodationListApi.Delete(a);

      snackbar("Le logement a été supprimé avec succès !");
      await accommodations.reloadAccommodationsList();
    } catch (e) {
      console.error("Failed to delete accommodation!", e);
      setError(`Échec de la suppression du logement! ${e}`);
    } finally {
      loading.hide();
    }
  };

  return (
    <FamilyCard error={error} success={success} style={{ width: CARDS_WIDTH }}>
      <CardContent>
        <Typography gutterBottom variant="h5" component="div">
          Logements
        </Typography>

        {/* Display the list of accommodations */}
        {accommodations.accommodations.isEmpty && (
          <div style={{ textAlign: "center", margin: "25px" }}>
            Aucun logement enregistré pour le moment !
          </div>
        )}
        {accommodations.accommodations.fullList.map((a) => (
          <AccommodationCard
            accommodation={a}
            onRequestUpdate={requestUpdateAccommodation}
            onRequestDelete={deleteAccommodation}
          />
        ))}

        {family.family.is_admin && (
          <Button
            startIcon={<AddIcon />}
            variant="outlined"
            color="info"
            fullWidth
            onClick={createAccommodation}
            size={"large"}
          >
            Ajouter un logement
          </Button>
        )}
      </CardContent>
    </FamilyCard>
  );
}

function AccommodationCard(p: {
  accommodation: Accommodation;
  onRequestUpdate: (a: Accommodation) => void;
  onRequestDelete: (a: Accommodation) => void;
}): React.ReactElement {
  const family = useFamily();
  return (
    <Card sx={{ minWidth: 275, margin: "10px 0px" }} variant="outlined">
      <CardContent>
        <Typography sx={{ fontSize: 14 }} color="text.secondary" gutterBottom>
          Mis à jour il y a <TimeWidget time={p.accommodation.time_update} />
        </Typography>
        <Typography variant="h5" component="div">
          <HouseIcon sx={{ color: "#" + p.accommodation.color }} />{" "}
          {p.accommodation.name}
        </Typography>
        <Typography sx={{ mb: 1.5 }} color="text.secondary">
          {p.accommodation.description}
        </Typography>
        <Typography variant="body2">
          <BoolIcon checked={p.accommodation.open_to_reservations} /> Ouvert aux
          réservations
          <br />
          <BoolIcon checked={!p.accommodation.need_validation} /> Réservation
          sans validation d'un administrateur
        </Typography>
      </CardContent>
      {family.family.is_admin && (
        <CardActions>
          <span style={{ flex: 1 }}></span>
          <Button
            size="small"
            onClick={() => p.onRequestUpdate(p.accommodation)}
          >
            Modifier
          </Button>
          <Button
            size="small"
            color="error"
            onClick={() => p.onRequestDelete(p.accommodation)}
          >
            Supprimer
          </Button>
        </CardActions>
      )}
    </Card>
  );
}

function BoolIcon(p: { checked?: boolean }): React.ReactElement {
  return p.checked ? (
    <CheckIcon color="success" />
  ) : (
    <CloseIcon color="error" />
  );
}

function AccommodationsCalURLsCard(): React.ReactElement {
  const key = React.useRef(0);

  const confirm = useConfirm();
  const loading = useLoadingMessage();

  const [error, setError] = React.useState<string>();
  const [success, setSuccess] = React.useState<string>();

  const [list, setList] = React.useState<
    AccommodationCalendarURL[] | undefined
  >();

  const family = useFamily();

  const createCalendarURLDialog = useCreateAccommodationCalendarURL();
  const calendarURLDialog = useInstallCalendarDialog();

  const load = async () => {
    setList(await AccommodationsCalendarURLApi.GetList(family.family));
  };

  const reload = () => {
    key.current += 1;
    setList(undefined);
  };

  const onRequestDelete = async (c: AccommodationCalendarURL) => {
    setError(undefined);
    setSuccess(undefined);
    try {
      if (
        !(await confirm(
          `Voulez-vous vraiment supprimer le calendrier '${c.name}' ? Cette opération est définitive !`
        ))
      )
        return;

      loading.show("Suppression du calendrier en cours...");

      await AccommodationsCalendarURLApi.Delete(c);

      setSuccess("Le calendrier a été supprimé avec succès !");
      reload();
    } catch (e) {
      console.error("Failed to delete accommodation!", e);
      setError(`Échec de la suppression du logement! ${e}`);
    } finally {
      loading.hide();
    }
  };

  const createCalendarURL = async () => {
    try {
      const newCal = await createCalendarURLDialog();

      if (!newCal) return;

      loading.show("Création du calendrier en cours...");

      const cal = await AccommodationsCalendarURLApi.Create(
        family.family,
        newCal
      );

      setSuccess("Le calendrier a été créé avec succès !");

      reload();

      calendarURLDialog(cal);
    } catch (e) {
      console.error("Failed to create new accommodation calendar URL!", e);
      setError(`Échec de la création du calendrier! ${e}`);
    } finally {
      loading.hide();
    }
  };

  return (
    <FamilyCard error={error} success={success} style={{ width: CARDS_WIDTH }}>
      <CardContent>
        <Typography gutterBottom variant="h5" component="div">
          URL de calendriers
        </Typography>
        <Typography>
          Vous pouvez, si vous le souhaitez, importer dans votre application de
          calendrier le planning de réservation des logements. Pour ce faire, il
          vous suffit de créer une URL de calendrier.
        </Typography>

        <Alert severity="info">
          Les calendriers créés ici ne sont visible que par vous. Vous ne pouvez
          pas manipuler les calendriers créés par les autres membres de la
          famille.
        </Alert>

        <Button
          startIcon={<AddIcon />}
          variant="outlined"
          color="info"
          fullWidth
          onClick={createCalendarURL}
          size={"large"}
        >
          Créer un calendrier
        </Button>

        <br />
        <br />

        <AsyncWidget
          ready={list !== undefined}
          loadKey={key.current}
          load={load}
          errMsg="Echec du chargement de la liste des calendriers !"
          build={() =>
            list?.length === 0 ? (
              <>
                <p style={{ textAlign: "center" }}>
                  Vous n'avez créé aucun calendrier pour le moment !
                </p>
              </>
            ) : (
              <>
                {list?.map((c) => (
                  <CalendarItem c={c} onRequestDelete={onRequestDelete} />
                ))}
              </>
            )
          }
        />
      </CardContent>
    </FamilyCard>
  );
}

function CalendarItem(p: {
  c: AccommodationCalendarURL;
  onRequestDelete: (c: AccommodationCalendarURL) => void;
}): React.ReactElement {
  const accommodations = useAccommodations();

  const installCal = useInstallCalendarDialog();

  return (
    <Card sx={{ minWidth: 275, margin: "10px 0px" }} variant="outlined">
      <CardContent>
        <Typography
          sx={{ fontSize: 14 }}
          color="text.secondary"
          gutterBottom
        ></Typography>
        <Typography variant="h5" component="div">
          {p.c.name}
        </Typography>
        <Typography sx={{ mb: 1.5 }} color="text.secondary">
          {p.c.accommodation_id
            ? accommodations.accommodations.get(p.c.accommodation_id)?.name
            : "Tous les logements"}
        </Typography>
        <Typography variant="body2">
          Créé il y a <TimeWidget time={p.c.time_create} />
          <br />
          Utilisé il y a <TimeWidget time={p.c.time_used} />
        </Typography>
      </CardContent>

      <CardActions>
        <span style={{ flex: 1 }}></span>
        <Button size="small" onClick={() => installCal(p.c)}>
          Installer
        </Button>
        <Button
          size="small"
          color="error"
          onClick={() => p.onRequestDelete(p.c)}
        >
          Supprimer
        </Button>
      </CardActions>
    </Card>
  );
}
