"use client";

import BusinessOutlinedIcon from "@mui/icons-material/BusinessOutlined";
import FileUploadOutlinedIcon from "@mui/icons-material/FileUploadOutlined";

import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import CircularProgress from "@mui/material/CircularProgress";
import Typography from "@mui/material/Typography";

import {
  type ChangeEvent,
  useRef,
  useState,
} from "react";

type Props = {
  title: string;
  description: string;

  logoUrl:
    | string
    | null;

  imageAlt:
    string;

  isUploading?:
    boolean;

  onUpload:
    (
      file: File,
    ) =>
      | Promise<void>
      | void;
};

const MAX_FILE_SIZE =
  5 *
  1024 *
  1024;

const ALLOWED_FILE_TYPES = [
  "image/png",
  "image/jpeg",
  "image/webp",
];

export function OrganizationLogoUploader({
  title,
  description,
  logoUrl,
  imageAlt,
  isUploading = false,
  onUpload,
}: Props) {
  const inputRef =
    useRef<HTMLInputElement | null>(
      null,
    );

  const [
    previewUrl,
    setPreviewUrl,
  ] =
    useState<string | null>(
      null,
    );

  const [
    error,
    setError,
  ] =
    useState<string | null>(
      null,
    );

  const displayedLogo =
    previewUrl ??
    logoUrl;

  function chooseFile() {
    if (isUploading) {
      return;
    }

    inputRef.current?.click();
  }

  async function handleFileChange(
    event: ChangeEvent<HTMLInputElement>,
  ) {
    const file =
      event.target.files?.[0];

    event.target.value =
      "";

    if (!file) {
      return;
    }

    if (
      !ALLOWED_FILE_TYPES.includes(
        file.type,
      )
    ) {
      setError(
        "Only PNG, JPG, JPEG or WEBP files are allowed.",
      );

      return;
    }

    if (
      file.size >
      MAX_FILE_SIZE
    ) {
      setError(
        "Logo size must not exceed 5MB.",
      );

      return;
    }

    setError(
      null,
    );

    const localPreview =
      URL.createObjectURL(
        file,
      );

    setPreviewUrl(
      localPreview,
    );

    try {
      await onUpload(
        file,
      );
    } catch (
      caughtError: unknown
    ) {
      setError(
        caughtError instanceof Error
          ? caughtError.message
          : "Unable to upload logo.",
      );
    } finally {
      URL.revokeObjectURL(
        localPreview,
      );
    }
  }

  return (
    <Box
      sx={{
        p:
          2,

        display:
          "grid",

        gridTemplateColumns: {
          xs:
            "1fr",

          sm:
            "150px minmax(0, 1fr)",
        },

        gap:
          2,

        border:
          "1px solid",

        borderColor:
          "divider",

        borderRadius:
          1.5,
      }}
    >
      <Box
        sx={{
          width:
            150,

          height:
            120,

          mx: {
            xs:
              "auto",

            sm:
              0,
          },

          p:
            1,

          bgcolor:
            "common.white",

          border:
            "1px solid",

          borderColor:
            "divider",

          borderRadius:
            1.5,

          display:
            "grid",

          placeItems:
            "center",

          overflow:
            "hidden",
        }}
      >
        {displayedLogo ? (
          <Box
            component="img"
            src={
              displayedLogo
            }
            alt={
              imageAlt
            }
            sx={{
              width:
                "100%",

              height:
                "100%",

              objectFit:
                "contain",
            }}
          />
        ) : (
          <BusinessOutlinedIcon
            sx={{
              fontSize:
                48,

              color:
                "text.secondary",
            }}
          />
        )}
      </Box>

      <Box>
        <Typography
          sx={{
            fontSize:
              14.5,

            fontWeight:
              700,
          }}
        >
          {title}
        </Typography>

        <Typography
          sx={{
            mt:
              0.5,

            color:
              "text.secondary",

            fontSize:
              13,

            lineHeight:
              1.6,
          }}
        >
          {description}
        </Typography>

        <Button
          type="button"
          variant="outlined"
          disabled={
            isUploading
          }
          onClick={
            chooseFile
          }
          startIcon={
            isUploading
              ? (
                  <CircularProgress
                    size={17}
                    color="inherit"
                  />
                )
              : (
                  <FileUploadOutlinedIcon />
                )
          }
          sx={{
            mt:
              1.5,

            textTransform:
              "none",

            fontWeight:
              600,
          }}
        >
          {isUploading
            ? "Uploading..."
            : "Change Logo"}
        </Button>

        {error && (
          <Typography
            sx={{
              mt:
                1,

              color:
                "error.main",

              fontSize:
                12.5,
            }}
          >
            {error}
          </Typography>
        )}

        <input
          ref={
            inputRef
          }
          hidden
          type="file"
          accept="image/png,image/jpeg,image/webp"
          disabled={
            isUploading
          }
          onChange={(
            event,
          ) => {
            void handleFileChange(
              event,
            );
          }}
        />
      </Box>
    </Box>
  );
}