import React from "react";

import CommentIcon from "@mui/icons-material/Comment";
import DeleteIcon from "@mui/icons-material/Delete";
import WarningIcon from "@mui/icons-material/Warning";
import Avatar from "@mui/material/Avatar";
import Divider from "@mui/material/Divider";
import FormControl from "@mui/material/FormControl";
import FormControlLabel from "@mui/material/FormControlLabel";
import IconButton from "@mui/material/IconButton";
import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
import ListItemAvatar from "@mui/material/ListItemAvatar";
import ListItemText from "@mui/material/ListItemText";
import Radio from "@mui/material/Radio";
import RadioGroup from "@mui/material/RadioGroup";
import Typography from "@mui/material/Typography";

import { useSnackbar } from "notistack";

import Card from "../../../components/Card";
import CardActions from "../../../components/Card/CardActions";
import CardContent from "../../../components/Card/CardContent";
import CardFieldText from "../../../components/Card/CardFieldText";
import CardHeader from "../../../components/Card/CardHeader";
import CardRow from "../../../components/Card/CardRow";
import CardSaveButton from "../../../components/Card/CardSaveButton";
import { useApi } from "../../../contexts/ApiContext";
import { useCardContext } from "../../../contexts/CardContext";
import { useI18n } from "../../../contexts/I18nContext";
import { useUser } from "../../../contexts/UserContext";
import { ContribComponent, LimitOffset } from "../../../types";
import { hasPermission } from "../../../util/has_permission";
import { AdminNote } from "../types/notes";

interface SelectOption {
  id: string;
  label: string;
}

interface AdminNoteFormProps {
  noteTypes: SelectOption[];
}

interface AdminNoteActionsProps {
  note: AdminNote;
  handleDelete: (note: AdminNote) => Promise<string>;
}

interface AdminNoteFormValues {
  body: string;
}

const formatDateTime = (dateString: string) => {
  return new Date(dateString).toLocaleString("sv-SE", {
    year: "numeric",
    month: "numeric",
    day: "numeric",
    hour: "numeric",
    minute: "numeric",
  });
};

const AdminNoteForm: React.FC<AdminNoteFormProps> = ({ noteTypes }) => {
  const { isEditing } = useCardContext();
  const { t } = useI18n();

  if (isEditing) {
    return (
      <CardContent>
        <CardRow>
          <FormControl fullWidth>
            <RadioGroup row defaultValue={noteTypes[0].id} name="note_type">
              {noteTypes.map((opt) => (
                <FormControlLabel
                  key={opt.id}
                  control={<Radio size="small" />}
                  label={opt.label}
                  value={opt.id}
                />
              ))}
            </RadioGroup>
          </FormControl>
        </CardRow>

        <CardRow>
          <CardFieldText
            fullWidth
            multiline
            required
            defaultValue={""}
            formName="body"
            label={t("Note")}
            minRows={2}
          />
        </CardRow>
      </CardContent>
    );
  }

  return <></>;
};

const AdminNoteActions: React.FC<AdminNoteActionsProps> = ({ note, handleDelete }) => {
  const { isEditing } = useCardContext();
  const { enqueueSnackbar } = useSnackbar();

  if (isEditing) {
    return (
      <IconButton
        aria-label="delete"
        edge="end"
        onClick={async () => {
          const success = await handleDelete(note);
          if (success != null) {
            enqueueSnackbar(success, { variant: "success" });
          }
        }}
      >
        <DeleteIcon />
      </IconButton>
    );
  }

  return <></>;
};

const AdminNotesSidebar: ContribComponent<LimitOffset<AdminNote>> = ({
  data: { next: _next, previous: _previous, results },
  params,
  refresh,
}) => {
  const api = useApi();
  const { user } = useUser();
  const { t } = useI18n();

  const createAction = api.operations["admin.notes:create-for-object"];
  const noteTypeValues = createAction?.request?.body?.schema?.properties?.note_type?.enum ?? [];
  const noteTypeLabels = createAction?.request?.body?.schema?.properties?.note_type?.labels ?? [];
  const noteTypeOptions = noteTypeValues.map((key: string, i: number) => {
    return { id: key, label: noteTypeLabels[i] ?? key };
  });

  const handleSave = async (values: AdminNoteFormValues) => {
    const action = api.operations["admin.notes:create-for-object"];
    if (!action) {
      throw new Error('Invalid action "admin.notes:create-for-object".');
    }

    const response = await action.call({
      params,
      body: { ...values },
    });

    if (!response.ok) {
      console.error("[ADMIN_NOTES]", response);
      throw new Error("creating admin note.");
    }

    refresh();
    return t("Note created");
  };

  const handleDelete = async (note: AdminNote) => {
    const action = api.operations["admin.notes:update"];
    if (!action) {
      throw new Error('Invalid action "admin.notes:update.');
    }

    const response = await action.call({
      params: {
        id: note.id,
      },
      body: {
        archived: true,
      },
    });

    if (!response.ok) {
      console.error("[ADMIN_NOTES]", response);
      throw new Error("archiving admin note.");
    }

    refresh();
    return t("Note archived");
  };

  return (
    <Card
      columns={1}
      isEditable={hasPermission(user, "administration.add_adminnote")}
      onSubmit={handleSave}
    >
      <CardHeader title={t("Notes")} />

      <AdminNoteForm noteTypes={noteTypeOptions} />

      <CardActions>
        <CardSaveButton label="Create" />
      </CardActions>

      <CardContent
        sx={{
          p: 0,
          "&:last-child": { pb: 0 },
        }}
      >
        <List dense>
          {results.map((note, i) => {
            return (
              <>
                <ListItem
                  key={note.id}
                  secondaryAction={<AdminNoteActions handleDelete={handleDelete} note={note} />}
                >
                  <ListItemAvatar>
                    <Avatar
                      sx={{
                        bgcolor: ["WARNING", "NOTICE"].includes(note.note_type)
                          ? "warning.main"
                          : null,
                      }}
                    >
                      {
                        /* TODO: Allow custom icons */
                        ["WARNING", "NOTICE"].includes(note.note_type) ? (
                          <WarningIcon />
                        ) : (
                          <CommentIcon />
                        )
                      }
                    </Avatar>
                  </ListItemAvatar>
                  <ListItemText
                    primary={
                      <Typography
                        sx={{
                          overflowWrap: "anywhere",
                          whiteSpace: "pre-wrap",
                          paddingBottom: "10px",
                        }}
                        variant="body1"
                      >
                        {note.body}
                      </Typography>
                    }
                    secondary={
                      <Typography color="text.secondary" variant="caption">
                        {note.author.username}
                        <br />
                        {formatDateTime(note.date_created)}
                        <br />
                      </Typography>
                    }
                  />
                </ListItem>
                {i != results.length - 1 ? <Divider component="li" variant="middle" /> : null}
              </>
            );
          })}
        </List>
      </CardContent>
    </Card>
  );
};

export default AdminNotesSidebar;
