import { Controller, useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { Button } from "@/shared/common/ui/button";
import { Label } from "@/shared/common/ui/label";
import { Input } from "@/shared/common/ui/input";
import { Textarea } from "@/shared/common/ui/textarea";
import { Alert, AlertDescription, AlertTitle } from "@/shared/common/ui/alert";
import { AlertCircle, Loader2, Upload, X } from "lucide-react";
import { useEffect, useMemo, useRef, useState } from "react";
import { useNavigate, useParams, useLocation } from "react-router-dom";
import {
  useTemplate,
  useTemplateWithPresigned,
  useTemplateMutations,
  useResourceTypes,
} from "../hooks/useTemplates";
import { toast } from "sonner";
import { useTranslation } from "react-i18next";
import { useErrorHandler } from "@/shared/hooks/useErrorHandler";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/shared/common/ui/select";

const MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024;
const ACCEPTED_FILE_TYPES = new Set([
  "image/png",
  "image/jpeg",
  "image/gif",
  "image/webp",
  "application/pdf",
]);

type FormData = {
  resourceTypeId: string;
  nameAm: string;
  nameEn: string;
  descriptionAm?: string;
  descriptionEn?: string;
  file?: FileList;
};

const buildTemplateFormSchema = (
  getRequireFile: () => boolean,
  translate: (key: string, fallback?: string) => string,
) =>
  z
    .object({
      resourceTypeId: z
        .string()
        .min(
          1,
          translate("template.resourceTypeRequired", "Resource type is required"),
        ),
      nameAm: z
        .string()
        .trim()
        .min(1, translate("template.nameRequired", "Name is required")),
      nameEn: z
        .string()
        .trim()
        .min(1, translate("template.nameRequired", "Name is required")),
      descriptionAm: z.string().optional(),
      descriptionEn: z.string().optional(),
      file: z.custom<FileList | undefined>().optional(),
    })
    .superRefine((data, ctx) => {
      const fileList = data.file;
      const selectedFile = fileList?.[0];
      const requireFile = getRequireFile();

      if (requireFile && !selectedFile) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: translate("template.fileRequired", "File is required"),
          path: ["file"],
        });
        return;
      }

      if (!selectedFile) return;

      if (!ACCEPTED_FILE_TYPES.has(selectedFile.type)) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: translate(
            "template.invalidFileType",
            "Only PNG, JPG, GIF, WebP, and PDF files are allowed",
          ),
          path: ["file"],
        });
      }

      if (selectedFile.size > MAX_FILE_SIZE_BYTES) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: translate(
            "template.fileTooLarge",
            "File must be 50MB or smaller",
          ),
          path: ["file"],
        });
      }
    });

export const TemplateForm = () => {
  const { id } = useParams();
  const location = useLocation();
  const navigate = useNavigate();
  const { t } = useTranslation();
  const { getErrorMessage } = useErrorHandler(t);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [submitError, setSubmitError] = useState<string | null>(null);
  const [filePreview, setFilePreview] = useState<string>("");
  const [fileName, setFileName] = useState<string>("");

  // Get resourceTypeId from location state (passed from list page)
  const resourceTypeIdFromState =
    ((location.state as Record<string, unknown>)?.resourceTypeId as string) ||
    "";

  const { data: template, isLoading: isLoadingTemplate } = useTemplate(
    id || "",
  );

  // Use the presigned version if we have resourceTypeId from state
  const { data: templateWithPresigned, isLoading: isLoadingPresigned } =
    useTemplateWithPresigned(resourceTypeIdFromState, id || "");

  // Use presigned version if available, otherwise fall back to regular template
  const templateData = resourceTypeIdFromState
    ? templateWithPresigned
    : template;
  const isLoadingTemplate2 = resourceTypeIdFromState
    ? isLoadingPresigned
    : isLoadingTemplate;

  const { data: resourceTypesData } = useResourceTypes();
  const { create, update } = useTemplateMutations();

  const hasExistingFile = Boolean(
    templateData?.fileInfo?.originalname || templateData?.presigned,
  );
  const requireFile = !hasExistingFile;
  const requireFileRef = useRef(requireFile);
  requireFileRef.current = requireFile;

  const translate = (key: string, fallback?: string) =>
    t(key, { defaultValue: fallback ?? key });

  const templateFormSchema = useMemo(
    () => buildTemplateFormSchema(() => requireFileRef.current, translate),
    [t],
  );

  const defaultValues = useMemo(
    () => ({
      resourceTypeId:
        templateData?.resourceTypeId || resourceTypeIdFromState || "",
      nameAm: templateData?.name?.am || "",
      nameEn: templateData?.name?.en || "",
      descriptionAm: templateData?.description?.am || "",
      descriptionEn: templateData?.description?.en || "",
    }),
    [templateData, resourceTypeIdFromState],
  );

  const {
    register,
    handleSubmit,
    watch,
    reset,
    control,
    formState: { errors },
  } = useForm<FormData>({
    resolver: zodResolver(templateFormSchema),
    defaultValues,
  });

  useEffect(() => {
    if (templateData) {
      reset(defaultValues);
      if (templateData.presigned) {
        setFilePreview(templateData.presigned);
      }
      if (templateData.fileInfo?.originalname) {
        setFileName(templateData.fileInfo.originalname);
      }
    }
  }, [templateData, defaultValues, reset]);

  const fileInput = watch("file")?.[0];

  useEffect(() => {
    if (fileInput) {
      const url = URL.createObjectURL(fileInput);
      setFilePreview(url);
      setFileName(fileInput.name);
      return () => URL.revokeObjectURL(url);
    }
  }, [fileInput]);

  const handleFormSubmit = async (formData: FormData) => {
    setIsSubmitting(true);
    setSubmitError(null);
    try {
      const file = formData.file?.[0];
      const payload = {
        resourceTypeId: formData.resourceTypeId,
        name: {
          am: formData.nameAm,
          en: formData.nameEn,
        },
        description: {
          am: formData.descriptionAm ?? "",
          en: formData.descriptionEn ?? "",
        },
        fileInfo: file
          ? {
              fileName: file.name,
              contentType: file.type,
              size: file.size,
              originalname: file.name,
            }
          : undefined,
      };

      if (id) {
        await update.mutateAsync({
          id,
          ...payload,
          fileData: file ? { file, uploadUrl: "" } : undefined,
        });
        toast.success(t("template.updated", "Resource updated successfully"));
      } else {
        await create.mutateAsync({
          ...payload,
          fileData: file ? { file, uploadUrl: "" } : undefined,
        });
        toast.success(t("template.created", "Resource created successfully"));
      }

      navigate(
        "/user-management/web-management/TemplateConfiguration/templates",
      );
    } catch (error) {
      setSubmitError(await getErrorMessage(error));
    } finally {
      setIsSubmitting(false);
    }
  };

  if (isLoadingTemplate2) {
    return (
      <div className="flex items-center justify-center p-8">
        <Loader2 className="h-8 w-8 animate-spin text-purple-600" />
      </div>
    );
  }

  return (
    <div className="max-h-[80vh] overflow-y-auto p-6 bg-white rounded-xl border border-gray-200 shadow-sm">
      <form onSubmit={handleSubmit(handleFormSubmit)} className="space-y-6">
        {/* Header */}
        <div className="mb-6">
          <h2 className="text-2xl font-bold text-gray-900">
            {id
              ? t("template.edit", "Edit Resource")
              : t("template.create", "Create Resource")}
          </h2>
          <p className="text-gray-600 mt-1">
            {id
              ? t("template.editDescription", "Update resource configuration")
              : t(
                  "template.createDescription",
                  "Create a new resource for style settings",
                )}
          </p>
        </div>

        {submitError && (
          <Alert className="border-red-200 bg-red-50/80 text-red-950 shadow-sm dark:border-red-900/60 dark:bg-red-950/30 dark:text-red-100">
            <AlertCircle className="h-4 w-4" />
            <div className="flex w-full items-start justify-between gap-3">
              <div className="space-y-1">
                <AlertTitle className="text-sm font-semibold">
                  {t("template.submitErrorTitle", "Could not save resource")}
                </AlertTitle>
                <AlertDescription className="text-sm text-red-800 dark:text-red-200">
                  {submitError}
                </AlertDescription>
              </div>
              <Button
                type="button"
                variant="ghost"
                size="icon"
                className="h-7 w-7 shrink-0 text-red-700 hover:bg-red-100 hover:text-red-900 dark:text-red-200 dark:hover:bg-red-900/40"
                onClick={() => setSubmitError(null)}
                aria-label={t("common.dismiss", "Dismiss")}
              >
                <X className="h-4 w-4" />
              </Button>
            </div>
          </Alert>
        )}

        {/* Resource Type */}
        <div className="space-y-2">
          <Label htmlFor="resourceTypeId" className="text-gray-700 font-medium">
            {t("template.resourceType", "Resource Type")} *
          </Label>
          <Controller
            name="resourceTypeId"
            control={control}
            render={({ field }) => (
              <Select value={field.value} onValueChange={field.onChange}>
                <SelectTrigger className="w-full">
                  <SelectValue
                    placeholder={t(
                      "template.selectResourceType",
                      "Select resource type",
                    )}
                  />
                </SelectTrigger>
                <SelectContent>
                  {resourceTypesData?.items?.map((type) => (
                    <SelectItem key={type.id} value={type.id}>
                      {type.name.en} ({type.name.am})
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            )}
          />
          {errors.resourceTypeId && (
            <p className="text-red-500 text-sm">
              {errors.resourceTypeId.message}
            </p>
          )}
        </div>

        {/* Names Section */}
        <div className="bg-gray-50 p-5 rounded-lg border border-gray-100 space-y-4">
          <h3 className="text-lg font-semibold text-gray-800 flex items-center">
            <div className="h-1 w-4 bg-primary-500 mr-2 rounded-full"></div>
            {t("template.names", "Names")}
          </h3>

          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
            <div className="space-y-2">
              <Label htmlFor="nameAm" className="text-gray-700">
                {t("template.nameAmharic", "Name (Amharic)")} *
              </Label>
              <Input
                id="nameAm"
                placeholder={t(
                  "template.enterNameAmharic",
                  "Enter name in Amharic",
                )}
                {...register("nameAm")}
                className="border-gray-300"
              />
              {errors.nameAm && (
                <p className="text-red-500 text-sm">{errors.nameAm.message}</p>
              )}
            </div>

            <div className="space-y-2">
              <Label htmlFor="nameEn" className="text-gray-700">
                {t("template.nameEnglish", "Name (English)")} *
              </Label>
              <Input
                id="nameEn"
                placeholder={t(
                  "template.enterNameEnglish",
                  "Enter name in English",
                )}
                {...register("nameEn")}
                className="border-gray-300"
              />
              {errors.nameEn && (
                <p className="text-red-500 text-sm">{errors.nameEn.message}</p>
              )}
            </div>
          </div>
        </div>

        {/* Descriptions Section */}
        <div className="bg-gray-50 p-5 rounded-lg border border-gray-100 space-y-4">
          <h3 className="text-lg font-semibold text-gray-800 flex items-center">
            <div className="h-1 w-4 bg-green-500 mr-2 rounded-full"></div>
            {t("template.descriptions", "Descriptions")}
          </h3>

          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
            <div className="space-y-2">
              <Label htmlFor="descriptionAm" className="text-gray-700">
                {t("template.descriptionAmharic", "Description (Amharic)")}
              </Label>
              <Textarea
                id="descriptionAm"
                placeholder={t(
                  "template.enterDescriptionAmharic",
                  "Enter description in Amharic",
                )}
                {...register("descriptionAm")}
                className="border-gray-300 min-h-24"
              />
            </div>

            <div className="space-y-2">
              <Label htmlFor="descriptionEn" className="text-gray-700">
                {t("template.descriptionEnglish", "Description (English)")}
              </Label>
              <Textarea
                id="descriptionEn"
                placeholder={t(
                  "template.enterDescriptionEnglish",
                  "Enter description in English",
                )}
                {...register("descriptionEn")}
                className="border-gray-300 min-h-24"
              />
            </div>
          </div>
        </div>

        {/* File Upload Section */}
        <div className="bg-gray-50 p-5 rounded-lg border border-gray-100 space-y-4">
          <h3 className="text-lg font-semibold text-gray-800 flex items-center">
            <div className="h-1 w-4 bg-orange-500 mr-2 rounded-full"></div>
            {t("template.file", "File")}
          </h3>

          <div className="space-y-3">
            <Label htmlFor="file" className="text-gray-700">
              {t("template.uploadFile", "Upload File")}
              {requireFile ? " *" : ""}
            </Label>

            {filePreview && (
              <div className="flex items-center justify-between p-3 bg-white border border-gray-200 rounded-lg">
                <span className="text-sm text-gray-700 truncate">
                  {fileName}
                </span>
              </div>
            )}

            <div className="relative">
              <input
                id="file"
                type="file"
                {...register("file")}
                className="hidden"
                accept=".png,.jpg,.jpeg,.gif,.webp,.pdf"
              />
              <label
                htmlFor="file"
                className="flex items-center justify-center w-full p-6 border-2 border-dashed border-gray-300 rounded-lg cursor-pointer hover:border-purple-500 hover:bg-purple-50 transition-colors"
              >
                <div className="flex flex-col items-center">
                  <Upload className="h-8 w-8 text-gray-400 mb-2" />
                  <span className="text-sm font-medium text-gray-700">
                    {t("template.dragDrop", "Drag and drop or click to upload")}
                  </span>
                  <span className="text-xs text-gray-500 mt-1">
                    {t(
                      "template.fileTypes",
                      "PNG, JPG, GIF, WebP, PDF up to 50MB",
                    )}
                  </span>
                </div>
              </label>
            </div>
            {errors.file && (
              <p className="text-red-500 text-sm">{errors.file.message}</p>
            )}
          </div>
        </div>

        {/* Actions */}
        <div className="flex justify-end gap-3 pt-6 border-t border-gray-200">
          <Button
            type="button"
            variant="outline"
            onClick={() =>
              navigate(
                "/user-management/web-management/TemplateConfiguration/templates",
              )
            }
            className="px-6"
          >
            {t("common.cancel", "Cancel")}
          </Button>
          <Button
            type="submit"
            disabled={isSubmitting}
            className="px-6 bg-purple-600 hover:bg-purple-700 text-white"
          >
            {isSubmitting ? (
              <span className="flex items-center gap-2">
                <Loader2 className="w-4 h-4 animate-spin" />
                {t("common.saving", "Saving...")}
              </span>
            ) : (
              t("common.save", "Save")
            )}
          </Button>
        </div>
      </form>
    </div>
  );
};
