"use client";

import {
  useEffect,
  useMemo,
  useState,
  type ChangeEvent,
  type DragEvent,
} from "react";

import CalendarMonthOutlinedIcon from "@mui/icons-material/CalendarMonthOutlined";
import CloudUploadOutlinedIcon from "@mui/icons-material/CloudUploadOutlined";
import Box from "@mui/material/Box";
import InputAdornment from "@mui/material/InputAdornment";
import Typography from "@mui/material/Typography";
import { alpha, useTheme, type Theme } from "@mui/material/styles";

import { AppDatePicker } from "@/components/ui/date-picker";
import {
  AppFormField,
  AppFormGrid,
  AppFormTextField,
  getFormBorderColor,
  getFormSoftBg,
} from "@/components/ui/form";
import { AppSelect, type AppSelectOption } from "@/components/ui/select";
import { PdfIcon } from "@/components/ui/icon";
import { AppTextEditor } from "@/components/ui/text-editor";
import { DocumentLink } from "@/components/ui/document-link";
import { getCurrentAndNextYearOptions } from "@/lib/date-utils";
import {
  formatFileSize,
  type UploadedFileMetadata,
} from "@/lib/document-file";

import type {
  CreateProgressReportDialogLabels,
  CreateProgressReportFormValues,
} from "./create-progress-report-dialog-types";

type CreateProgressReportDialogFieldsProps = {
  values: CreateProgressReportFormValues;
  errors: Partial<Record<keyof CreateProgressReportFormValues, string>>;
  labels: CreateProgressReportDialogLabels;
  existingAttachment?: UploadedFileMetadata | null;
  onChange: (
    field: "title" | "semester" | "description" | "year" | "deadline",
    value: string,
  ) => void;
  onAttachmentChange: (file: File | null) => void;
};

const PICKER_Z_INDEX = 1700;

const yearOptions: AppSelectOption[] = getCurrentAndNextYearOptions();

const semesterOptions: AppSelectOption[] = [
  { label: "S1", value: "S1" },
  { label: "S2", value: "S2" },
];

function deadlineToDate(value: string) {
  if (!value) {
    return null;
  }

  const [year, month, day] = value.split("-").map(Number);
  const date = new Date(year, month - 1, day);

  return Number.isNaN(date.getTime()) ? null : date;
}

function dateToDeadline(date: Date | null) {
  if (!date) {
    return "";
  }

  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");

  return `${year}-${month}-${day}`;
}

function getFormSelectMenuProps(theme: Theme) {
  return {
    sx: { zIndex: PICKER_Z_INDEX },
    slotProps: {
      paper: {
        sx: {
          mt: 0.6,
          maxHeight: 254,
          borderRadius: "12px",
          bgcolor: theme.palette.background.paper,
          color: theme.palette.text.primary,
          border: `1px solid ${getFormBorderColor(theme)}`,
          boxShadow:
            theme.palette.mode === "dark"
              ? "0px 12px 28px rgba(0, 0, 0, 0.45)"
              : "0px 0px 10.6px rgba(0, 0, 0, 0.1)",
          overflow: "hidden",
          "& .MuiList-root": {
            py: 1.5,
            maxHeight: 252,
            overflowY: "auto",
            "&::-webkit-scrollbar": { width: 6 },
            "&::-webkit-scrollbar-thumb": {
              bgcolor:
                theme.palette.mode === "dark"
                  ? alpha(theme.palette.common.white, 0.22)
                  : "#A4A7AE",
              borderRadius: "3px",
            },
          },
          "& .MuiMenuItem-root": {
            minHeight: 40,
            px: 2.75,
            bgcolor: theme.palette.background.paper,
            color: theme.palette.text.primary,
            fontSize: 12,
            fontWeight: 500,
            "&:hover": {
              bgcolor: alpha(theme.palette.primary.main, 0.08),
            },
            "&.Mui-selected": {
              bgcolor: alpha(theme.palette.primary.main, 0.12),
            },
          },
        },
      },
    },
  };
}

function FieldError({ message }: { message?: string }) {
  if (!message) {
    return null;
  }

  return (
    <Typography sx={{ mt: 0.5, fontSize: 12, color: "error.main" }}>
      {message}
    </Typography>
  );
}

function AttachmentField({
  values,
  errors,
  labels,
  existingAttachment,
  onAttachmentChange,
}: CreateProgressReportDialogFieldsProps) {
  const theme = useTheme();
  const [uploadCompleted, setUploadCompleted] = useState(false);
  const hasExistingAttachment = Boolean(existingAttachment);
  const hasAttachment = Boolean(values.attachment) || hasExistingAttachment;
  const attachmentName = values.attachment
    ? values.attachment.name
    : (existingAttachment?.name ?? "-");
  const attachmentSize = values.attachment
    ? formatFileSize(values.attachment.size)
    : formatFileSize(existingAttachment?.size);
  const attachmentCompleted = values.attachment
    ? uploadCompleted
    : hasExistingAttachment;
  const attachmentCard = (
    <Box
      sx={{
        width: { xs: "100%", sm: 287 },
        height: 62,
        px: 1.5,
        display: "flex",
        alignItems: "center",
        gap: 1.5,
        borderRadius: "6px",
        bgcolor: getFormSoftBg(theme),
        overflow: "hidden",
      }}
    >
      <PdfIcon sx={{ fontSize: 40, flexShrink: 0 }} />

      <Box sx={{ minWidth: 0, flex: 1 }}>
        <Typography
          noWrap
          sx={{
            fontSize: 12,
            fontWeight: 500,
            color: theme.palette.text.primary,
          }}
        >
          {attachmentName}
        </Typography>
        <Typography
          sx={{
            mt: 1.5,
            fontSize: 12,
            lineHeight: 1.24,
            color: theme.palette.text.secondary,
          }}
        >
          {attachmentSize}
        </Typography>
      </Box>

      <Box sx={{ width: 80, flexShrink: 0, textAlign: "center" }}>
        <Typography
          sx={{
            mb: 1,
            fontSize: 11,
            lineHeight: "16px",
            fontWeight: 500,
            color: theme.palette.text.secondary,
          }}
        >
          {attachmentCompleted ? "Completed" : "Uploading"}
        </Typography>
        <Box
          sx={{
            width: 80,
            height: 4,
            borderRadius: "16px",
            bgcolor: theme.palette.background.paper,
            overflow: "hidden",
          }}
        >
          <Box
            sx={{
              width: attachmentCompleted ? "100%" : "45%",
              height: "100%",
              borderRadius: "16px",
              bgcolor: "#22C55E",
              transition: "width 0.8s ease",
            }}
          />
        </Box>
      </Box>
    </Box>
  );

  useEffect(() => {
    const resetTimer = window.setTimeout(() => setUploadCompleted(false), 0);

    if (!values.attachment) {
      return () => window.clearTimeout(resetTimer);
    }

    const completeTimer = window.setTimeout(
      () => setUploadCompleted(true),
      800,
    );

    return () => {
      window.clearTimeout(resetTimer);
      window.clearTimeout(completeTimer);
    };
  }, [values.attachment]);

  function selectFile(file?: File) {
    if (!file) {
      return;
    }

    onAttachmentChange(file);
  }

  function handleFileChange(event: ChangeEvent<HTMLInputElement>) {
    selectFile(event.target.files?.[0]);

    // Clear the native input so the same file can be selected again.
    event.target.value = "";
  }

  function handleDrop(event: DragEvent<HTMLLabelElement>) {
    event.preventDefault();
    selectFile(event.dataTransfer.files?.[0]);
  }

  return (
    <AppFormField label={labels.attachment} required>
      {hasAttachment ? (
        <Box
          sx={{
            display: "flex",
            flexWrap: "wrap",
            alignItems: "center",
            gap: "22px",
          }}
        >
          <DocumentLink
            file={values.attachment ? null : existingAttachment}
            sx={{ display: "block" }}
          >
            {attachmentCard}
          </DocumentLink>

          <Box
            component="label"
            onDragOver={(event: DragEvent<HTMLLabelElement>) =>
              event.preventDefault()
            }
            onDrop={handleDrop}
            sx={{
              width: 77,
              height: 62,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              border: `1px dashed ${getFormBorderColor(theme)}`,
              borderRadius: "12px",
              bgcolor: getFormSoftBg(theme),
              cursor: "pointer",
              transition: "0.2s",
              "&:hover": {
                bgcolor: alpha(theme.palette.primary.main, 0.1),
                borderColor: theme.palette.primary.main,
              },
            }}
          >
            <CloudUploadOutlinedIcon
              sx={{ fontSize: 38, color: theme.palette.primary.main }}
            />
            <input
              hidden
              type="file"
              accept="application/pdf,.pdf"
              onChange={handleFileChange}
            />
          </Box>
        </Box>
      ) : (
        <Box
          component="label"
          onDragOver={(event: DragEvent<HTMLLabelElement>) =>
            event.preventDefault()
          }
          onDrop={handleDrop}
          sx={{
            height: 135,
            border: `1px dashed ${
              errors.attachment
                ? theme.palette.error.main
                : getFormBorderColor(theme)
            }`,
            borderRadius: "10px",
            bgcolor: getFormSoftBg(theme),
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            flexDirection: "column",
            cursor: "pointer",
            transition: "0.2s",
            "&:hover": {
              bgcolor: alpha(theme.palette.primary.main, 0.1),
              borderColor: theme.palette.primary.main,
            },
          }}
        >
          <CloudUploadOutlinedIcon
            sx={{
              mb: 0.5,
              fontSize: 34,
              color: theme.palette.primary.main,
            }}
          />

          <Typography
            sx={{
              fontSize: 11,
              color: theme.palette.text.secondary,
              fontWeight: 600,
            }}
          >
            <Box
              component="span"
              sx={{ color: theme.palette.primary.main, fontWeight: 700 }}
            >
              {labels.uploadText}
            </Box>{" "}
            {labels.uploadHint}
          </Typography>

          <Typography
            sx={{ fontSize: 10, color: theme.palette.text.secondary }}
          >
            {labels.fileTypeHint}
          </Typography>

          <input
            hidden
            type="file"
            accept="application/pdf,.pdf"
            onChange={handleFileChange}
          />
        </Box>
      )}

      <FieldError message={errors.attachment} />
    </AppFormField>
  );
}

export function CreateProgressReportDialogFields(
  props: CreateProgressReportDialogFieldsProps,
) {
  const theme = useTheme();
  const { values, errors, labels, onChange } = props;
  const selectMenuProps = getFormSelectMenuProps(theme);
  const availableYearOptions = useMemo(() => {
    if (
      !values.year ||
      yearOptions.some((option) => option.value === values.year)
    ) {
      return yearOptions;
    }

    return [{ label: values.year, value: values.year }, ...yearOptions];
  }, [values.year]);

  const calendarIcon = (
    <InputAdornment position="start">
      <CalendarMonthOutlinedIcon
        sx={{ fontSize: 20, color: "text.secondary" }}
      />
    </InputAdornment>
  );

  return (
    <Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
      <AppFormField label={labels.reportTitle} required>
        <AppFormTextField
          value={values.title}
          placeholder={labels.reportTitlePlaceholder}
          error={Boolean(errors.title)}
          helperText={errors.title}
          onChange={(event) => onChange("title", event.target.value)}
        />
      </AppFormField>

        <AppFormField
          label={labels.semester}
          required
          sx={{ width: { xs: "100%", sm: 180 }, maxWidth: "100%" }}
        >
          <AppSelect
            value={values.semester}
            options={semesterOptions}
            placeholder={labels.semesterPlaceholder}
            onChange={(value) => onChange("semester", value)}
            showPlaceholderOption={false}
            error={Boolean(errors.semester)}
            MenuProps={{
              sx: { zIndex: PICKER_Z_INDEX },
              slotProps: {
                paper: {
                  sx: {
                    mt: 0.6,
                    maxHeight: 254,
                    borderRadius: "12px",
                    bgcolor: theme.palette.background.paper,
                    color: theme.palette.text.primary,
                    border: `1px solid ${getFormBorderColor(theme)}`,
                    boxShadow:
                      theme.palette.mode === "dark"
                        ? "0px 12px 28px rgba(0, 0, 0, 0.45)"
                        : "0px 0px 10.6px rgba(0, 0, 0, 0.1)",
                    overflow: "hidden",
                    "& .MuiList-root": {
                      py: 1.5,
                      maxHeight: 252,
                      overflowY: "auto",
                    },
                    "& .MuiMenuItem-root": {
                      minHeight: 40,
                      px: 2.75,
                      bgcolor: theme.palette.background.paper,
                      color: theme.palette.text.primary,
                      fontSize: 12,
                      fontWeight: 500,
                      "&:hover": {
                        bgcolor: alpha(theme.palette.primary.main, 0.08),
                      },
                      "&.Mui-selected": {
                        bgcolor: alpha(theme.palette.primary.main, 0.12),
                      },
                    },
                  },
                },
              },
            }}
          />
          <FieldError message={errors.semester} />
        </AppFormField>

        <AppFormField label={labels.description} required>
          <AppTextEditor
            minRows={4}
            value={values.description}
            placeholder={labels.descriptionPlaceholder}
            onChange={(value) => onChange("description", value)}
          />
          <FieldError message={errors.description} />
        </AppFormField>

        <AppFormGrid>
          <AppFormField label={labels.year} required>
            <AppSelect
              value={values.year}
              options={availableYearOptions}
              placeholder={labels.yearPlaceholder}
              onChange={(value) => onChange("year", value)}
              showPlaceholderOption={false}
              startAdornment={calendarIcon}
              error={Boolean(errors.year)}
              MenuProps={selectMenuProps}
            />
            <FieldError message={errors.year} />
          </AppFormField>

          <AppFormField label={labels.deadline} required>
            <AppDatePicker
              value={deadlineToDate(values.deadline)}
              onChange={(date) => onChange("deadline", dateToDeadline(date))}
              placeholder={labels.deadlinePlaceholder}
              error={Boolean(errors.deadline)}
              popperZIndex={PICKER_Z_INDEX}
            />
            <FieldError message={errors.deadline} />
          </AppFormField>
        </AppFormGrid>

        <AttachmentField {...props} />
      </Box>
  );
}
