"use client";

import { useEffect, useRef, useState } from "react";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useRouter } from "next/navigation";
import { toast } from "sonner";
import * as z from "zod";
import { FileUploader } from "@/components/file-uploader";
import { Icons } from "@/components/icons";
import { DurationPicker } from "@/components/ui/duration-picker";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { scrollToFirstError, useAppForm } from "@/components/ui/tanstack-form";
import { isHRD } from "@/lib/auth/roles";
import {
  deleteCertificateMutation,
  uploadCertificatesMutation,
} from "../api/certificate-mutations";
import {
  createTrainingRecordMutation,
  updateTrainingRecordMutation,
} from "../api/mutations";
import {
  certificatesQueryOptions,
  userOptionsQueryOptions,
} from "../api/queries";
import type { TrainingRecord } from "../api/types";
import {
  isPublicTrainingType,
  publicTrainingAttachmentNotice,
  publicTrainingAttachmentRequiredMessage,
  trainingRecordCertificateAccept,
  trainingRecordCertificateMaxFiles,
  trainingRecordCertificateMaxSize,
} from "../constants/certificate-upload";
import {
  trainingRecordStatusLabelMap,
  type UiTrainingType,
  trainingTypeOptions,
} from "../constants/training-record-options";
import {
  trainingRecordSchema,
  type TrainingRecordFormValues,
} from "../schemas/training-record";
import {
  decimalHoursToMinutes,
  getDurationMinutes,
} from "../utils/time-utils";
import { TrainingRecordAttachmentList } from "./training-record-attachment-list";
import { TrainingRecordCourseCombobox } from "./training-record-course-combobox";

function isEmployeeEditableStatus(
  status: TrainingRecord["approval_status"] | null | undefined,
) {
  return status === "draft" || status === "needs_revision";
}

function getSubmitActionLabel(
  isEdit: boolean,
  status: TrainingRecord["approval_status"] | null | undefined,
) {
  if (!isEdit) {
    return "ส่งตรวจสอบ";
  }

  if (status === "needs_revision") {
    return "ส่งตรวจสอบอีกครั้ง";
  }

  if (status === "draft") {
    return "บันทึกประวัติการอบรม";
  }

  return "อัปเดตประวัติการอบรม";
}

function getPendingLabel(isEdit: boolean, mode: "draft" | "submit") {
  if (mode === "draft") {
    return isEdit ? "กำลังบันทึกฉบับร่าง..." : "กำลังสร้างฉบับร่าง...";
  }

  return isEdit ? "กำลังบันทึก..." : "กำลังส่งข้อมูล...";
}

function getFirstFieldError(error: unknown) {
  if (!error) return undefined;
  if (typeof error === "string") return error;
  if (
    typeof error === "object" &&
    "message" in error &&
    typeof error.message === "string"
  ) {
    return error.message;
  }

  return undefined;
}

export default function TrainingRecordForm({
  initialData,
  pageTitle,
  currentUser,
  businessRole,
  systemRole,
}: {
  initialData: TrainingRecord | null;
  pageTitle: string;
  currentUser: {
    id: string;
    name: string;
    employeeId: number | null;
  };
  businessRole: "IT" | "HRD" | "EMPLOYEE" | null;
  systemRole?: string | null;
}) {
  const router = useRouter();
  const isEdit = Boolean(initialData);
  const [pendingFiles, setPendingFiles] = useState<File[]>([]);
  const [attachmentError, setAttachmentError] = useState<string | null>(null);
  const submitModeRef = useRef<"draft" | "submit">("submit");
  const canManageAsHRD = isHRD({ businessRole, systemRole });
  const canEmployeeManageRecord =
    !initialData || isEmployeeEditableStatus(initialData.approval_status);
  const canManageRecord = canManageAsHRD || canEmployeeManageRecord;

  const { data: userOptions = [] } = useQuery({
    ...userOptionsQueryOptions(),
    enabled: canManageAsHRD,
  });
  const { data: certificateData } = useQuery({
    ...certificatesQueryOptions(initialData?.id ?? 0),
    enabled: isEdit && Boolean(initialData),
  });

  const createMutation = useMutation({
    ...createTrainingRecordMutation,
    onError: (error) => {
      toast.error(
        error instanceof Error
          ? error.message
          : "ไม่สามารถสร้างประวัติการอบรมได้",
      );
    },
  });

  const updateMutation = useMutation({
    ...updateTrainingRecordMutation,
    onError: (error) => {
      toast.error(
        error instanceof Error
          ? error.message
          : "ไม่สามารถอัปเดตประวัติการอบรมได้",
      );
    },
  });

  const uploadMutation = useMutation({
    ...uploadCertificatesMutation,
    onError: (error) => {
      toast.error(
        error instanceof Error ? error.message : "ไม่สามารถอัปโหลดใบรับรองได้",
      );
    },
  });

  const deleteMutation = useMutation({
    ...deleteCertificateMutation,
    onSuccess: () => {
      toast.success("ลบเอกสารเรียบร้อยแล้ว");
    },
    onError: () => {
      toast.error("ไม่สามารถลบเอกสารได้");
    },
  });

  const form = useAppForm({
    defaultValues: {
      employeeId: String(
        initialData?.employee_id ?? currentUser.employeeId ?? "",
      ),
      useCustomCourse: initialData ? initialData.course_id === null : false,
      courseId: initialData?.course_id ?? null,
      courseName: initialData?.course_name ?? "",
      customCourseName: initialData?.course_id
        ? ""
        : (initialData?.course_name ?? ""),
      trainingDate: initialData?.training_date
        ? initialData.training_date.slice(0, 10)
        : new Date().toISOString().slice(0, 10),
      trainingType: initialData?.training_type ?? "",
      submittedMinutes:
        getDurationMinutes(
          initialData?.submitted_minutes,
          initialData?.hours,
        ) ?? undefined,
      organizer: initialData?.organizer ?? "",
      note: initialData?.note ?? "",
    } as TrainingRecordFormValues,
    validators: {
      onSubmit: trainingRecordSchema,
    },
    onSubmitInvalid: () => {
      toast.error("กรุณาตรวจสอบข้อมูลที่จำเป็นให้ครบถ้วน");
      scrollToFirstError();
    },
    onSubmit: async ({ value }) => {
      if (!canManageRecord) {
        toast.error(
          "พนักงานแก้ไขรายการได้เฉพาะตอนสถานะฉบับร่างหรือขอแก้ไขเท่านั้น",
        );
        return;
      }

      if (!canManageAsHRD && !currentUser.employeeId) {
        toast.error("บัญชีนี้ยังไม่เชื่อมกับข้อมูลพนักงาน");
        return;
      }

      const filesToUpload = pendingFiles.filter((file) => {
        const isSupported = Object.keys(trainingRecordCertificateAccept).includes(
          file.type,
        );
        if (!isSupported) {
          toast.error(`${file.name}: ประเภทไฟล์ไม่รองรับ`);
          return false;
        }

        if (file.size > trainingRecordCertificateMaxSize) {
          toast.error(`${file.name}: ไฟล์มีขนาดเกิน 10MB`);
          return false;
        }

        return true;
      });
      const isPublicTraining = isPublicTrainingType(value.trainingType);
      const attachmentCount = existingCertificateCount + filesToUpload.length;
      const submitMode = submitModeRef.current;

      if (
        submitMode === "submit" &&
        isPublicTraining &&
        attachmentCount < 1
      ) {
        setAttachmentError(publicTrainingAttachmentRequiredMessage);
        toast.error(publicTrainingAttachmentRequiredMessage);
        return;
      }

      setAttachmentError(null);

      const payload = {
        employeeId: canManageAsHRD
          ? Number(value.employeeId)
          : Number(currentUser.employeeId ?? value.employeeId),
        courseId: value.useCustomCourse ? null : (value.courseId ?? null),
        courseName: value.useCustomCourse
          ? (value.customCourseName?.trim() ?? "")
          : value.courseName.trim(),
        trainingDate: value.trainingDate,
        trainingType: value.trainingType as UiTrainingType,
        submittedMinutes: value.submittedMinutes!,
        organizer: value.organizer,
        note: value.note,
        submissionMode: submitMode,
      };

      const draftPayload = {
        ...payload,
        submissionMode: "draft" as const,
      };

      const submitPayload = {
        ...payload,
        submissionMode: "submit" as const,
      };

      if (isEdit && initialData) {
        if (submitMode === "draft") {
          await updateMutation.mutateAsync({
            id: initialData.id,
            values: draftPayload,
          });

          if (filesToUpload.length) {
            await uploadMutation.mutateAsync({
              trainingRecordId: initialData.id,
              files: filesToUpload,
            });
            setPendingFiles([]);
          }

          toast.success("บันทึกฉบับร่างเรียบร้อยแล้ว");
          router.push("/dashboard/training-records");
          return;
        }

        await updateMutation.mutateAsync({
          id: initialData.id,
          values: draftPayload,
        });

        if (filesToUpload.length) {
          await uploadMutation.mutateAsync({
            trainingRecordId: initialData.id,
            files: filesToUpload,
          });
          setPendingFiles([]);
        }

        await updateMutation.mutateAsync({
          id: initialData.id,
          values: submitPayload,
        });

        toast.success("อัปเดตประวัติการอบรมเรียบร้อยแล้ว");
        router.push("/dashboard/training-records");
        return;
      }

      const response = await createMutation.mutateAsync(draftPayload);

      if (filesToUpload.length) {
        await uploadMutation.mutateAsync({
          trainingRecordId: response.training_record.id,
          files: filesToUpload,
        });
        setPendingFiles([]);
      }

      if (submitMode === "submit") {
        await updateMutation.mutateAsync({
          id: response.training_record.id,
          values: submitPayload,
        });
      }

      if (submitMode === "draft") {
        toast.success("บันทึกฉบับร่างเรียบร้อยแล้ว");
        router.push("/dashboard/training-records");
        return;
      }

      toast.success("บันทึกประวัติการอบรมเรียบร้อยแล้ว");
      router.push("/dashboard/training-records");
    },
  });
  const existingCertificateCount = certificateData?.certificates.length ?? 0;

  useEffect(() => {
    if (pendingFiles.length > 0 || existingCertificateCount > 0) {
      setAttachmentError(null);
    }
  }, [existingCertificateCount, pendingFiles.length]);

  const submitWithMode = (mode: "draft" | "submit") => {
    submitModeRef.current = mode;
    void form.handleSubmit();
  };

  const isSubmitting =
    createMutation.isPending ||
    updateMutation.isPending ||
    uploadMutation.isPending ||
    deleteMutation.isPending;
  const primaryActionLabel = getSubmitActionLabel(
    isEdit,
    initialData?.approval_status,
  );
  const attachmentItems = [
    ...(certificateData?.certificates.map((certificate) => ({
      id: certificate.id,
      fileName: certificate.file_name,
      fileSize: certificate.file_size,
      fileType: certificate.file_type,
      fileUrl: certificate.file_url,
      onDelete:
        initialData && canManageRecord
          ? () =>
              deleteMutation.mutate({
                trainingRecordId: initialData.id,
                certificateId: certificate.id,
              })
          : undefined,
      isDeleting: deleteMutation.isPending,
    })) ?? []),
    ...pendingFiles.map((file, index) => ({
      id: `pending-${file.name}-${index}`,
      fileName: file.name,
      fileSize: file.size,
      fileType: file.type,
      statusLabel: "รอบันทึก",
      onDelete: canManageRecord
        ? () =>
            setPendingFiles((current) =>
              current.filter((_, currentIndex) => currentIndex !== index),
            )
        : undefined,
      isDeleting: false,
    })),
  ];

  return (
    <Card className="mx-auto w-full">
      <CardHeader>
        <CardTitle className="text-left text-2xl font-bold">
          {pageTitle}
        </CardTitle>
      </CardHeader>
      <CardContent>
        {initialData ? (
          <div className="bg-muted/40 mb-6 rounded-lg border p-4">
            <div className="flex flex-col gap-2 md:flex-row md:items-center md:justify-between">
              <div>
                <div className="text-sm font-medium">สถานะปัจจุบัน</div>
                <div className="text-muted-foreground text-sm">
                  {trainingRecordStatusLabelMap[initialData.approval_status]}
                </div>
              </div>
              {initialData.reviewer_note ? (
                <div className="max-w-xl text-sm">
                  <span className="font-medium">หมายเหตุผู้ตรวจ: </span>
                  <span className="text-muted-foreground">
                    {initialData.reviewer_note}
                  </span>
                </div>
              ) : null}
            </div>
          </div>
        ) : null}

        {!canManageRecord ? (
          <Alert className="mb-6">
            <Icons.info className="h-4 w-4" />
            <AlertTitle>รายการนี้เป็นแบบอ่านอย่างเดียว</AlertTitle>
            <AlertDescription>
              พนักงานสามารถแก้ไขหรือลบประวัติการอบรมได้เฉพาะตอนสถานะฉบับร่างหรือขอแก้ไขเท่านั้น
            </AlertDescription>
          </Alert>
        ) : null}

        <form.AppForm>
          <form.Form className="space-y-8">
            <div className="grid grid-cols-1 gap-6 md:grid-cols-2">
              {canManageAsHRD ? (
                <form.AppField
                  name="employeeId"
                  validators={{
                    onBlur: z.string().min(1, "กรุณาเลือกพนักงาน"),
                  }}
                >
                  {(field) => (
                    <field.FieldSet>
                      <field.Field>
                        <field.FieldLabel htmlFor={field.name}>
                          พนักงาน *
                        </field.FieldLabel>
                        <Select
                          value={field.state.value}
                          onValueChange={field.handleChange}
                          onOpenChange={(open) => {
                            if (!open) field.handleBlur();
                          }}
                          disabled={isSubmitting || !canManageRecord}
                        >
                          <SelectTrigger
                            id={field.name}
                            aria-invalid={
                              field.state.meta.isTouched &&
                              !field.state.meta.isValid
                            }
                          >
                            <SelectValue placeholder="เลือกพนักงาน" />
                          </SelectTrigger>
                          <SelectContent>
                            {userOptions.map((option) => (
                              <SelectItem
                                key={option.value}
                                value={option.value}
                              >
                                {option.label}
                              </SelectItem>
                            ))}
                          </SelectContent>
                        </Select>
                      </field.Field>
                      <field.FieldError />
                    </field.FieldSet>
                  )}
                </form.AppField>
              ) : (
                <div className="space-y-2">
                  <div className="text-sm font-medium">พนักงาน</div>
                  <div className="bg-muted/40 rounded-md border px-3 py-2 text-sm">
                    {currentUser.name}
                  </div>
                </div>
              )}

              <form.Subscribe selector={(state) => state.values}>
                {(values) => (
                  <form.AppField name="courseId">
                    {(field) => (
                      <field.FieldSet>
                        <field.Field>
                          <TrainingRecordCourseCombobox
                            value={values.courseId}
                            customCourseName={values.customCourseName ?? ""}
                            selectedCourseName={values.courseName}
                            useCustomCourse={values.useCustomCourse ?? false}
                            disabled={isSubmitting || !canManageRecord}
                            onBlur={field.handleBlur}
                            selectionError={getFirstFieldError(
                              field.state.meta.errors[0],
                            )}
                            customCourseNameError={getFirstFieldError(
                              form.getFieldMeta("customCourseName")
                                ?.errors?.[0],
                            )}
                            onSelectCourse={(course) => {
                              form.setFieldValue("useCustomCourse", false);
                              form.setFieldValue("courseId", course.id);
                              form.setFieldValue("courseName", course.name);
                              form.setFieldValue("customCourseName", "");

                              if (course.organizer) {
                                form.setFieldValue(
                                  "organizer",
                                  course.organizer,
                                );
                              }

                              if (!Number.isNaN(course.standard_hours)) {
                                form.setFieldValue(
                                  "submittedMinutes",
                                  decimalHoursToMinutes(course.standard_hours),
                                );
                              }
                            }}
                            onSelectCustom={() => {
                              form.setFieldValue("useCustomCourse", true);
                              form.setFieldValue("courseId", null);
                              form.setFieldValue("courseName", "");
                            }}
                            onBackToCourseSelect={() => {
                              form.setFieldValue("useCustomCourse", false);
                              form.setFieldValue("courseId", null);
                              form.setFieldValue("courseName", "");
                              form.setFieldValue("customCourseName", "");
                            }}
                            onCustomCourseNameChange={(nextValue) => {
                              form.setFieldValue("useCustomCourse", true);
                              form.setFieldValue("courseId", null);
                              form.setFieldValue("customCourseName", nextValue);
                              form.setFieldValue("courseName", nextValue);
                            }}
                          />
                        </field.Field>
                        <field.FieldError />
                      </field.FieldSet>
                    )}
                  </form.AppField>
                )}
              </form.Subscribe>

              <form.AppField
                name="trainingDate"
                validators={{
                  onBlur: z
                    .string()
                    .min(1, "กรุณาเลือกวันที่อบรม")
                    .refine(
                      (value) => !Number.isNaN(Date.parse(value)),
                      "วันที่อบรมไม่ถูกต้อง",
                    ),
                }}
              >
                {(field) => (
                  <field.FieldSet>
                    <field.Field>
                      <field.FieldLabel htmlFor={field.name}>
                        วันที่อบรม *
                      </field.FieldLabel>
                      <Input
                        id={field.name}
                        type="date"
                        value={field.state.value ?? ""}
                        disabled={isSubmitting || !canManageRecord}
                        onBlur={field.handleBlur}
                        onChange={(event) =>
                          field.handleChange(event.target.value)
                        }
                        aria-invalid={
                          field.state.meta.isTouched &&
                          !field.state.meta.isValid
                        }
                      />
                    </field.Field>
                    <field.FieldError />
                  </field.FieldSet>
                )}
              </form.AppField>

              <form.AppField
                name="trainingType"
                validators={{
                  onBlur: z.string().min(1, "กรุณาเลือกประเภทการอบรม"),
                }}
              >
                {(field) => (
                  <field.FieldSet>
                    <field.Field>
                      <field.FieldLabel htmlFor={field.name}>
                        ประเภทการอบรม *
                      </field.FieldLabel>
                      <Select
                        value={field.state.value ?? ""}
                        onValueChange={(value) => {
                          field.handleChange(value);
                          if (!isPublicTrainingType(value)) {
                            setAttachmentError(null);
                          }
                        }}
                        onOpenChange={(open) => {
                          if (!open) field.handleBlur();
                        }}
                        disabled={isSubmitting || !canManageRecord}
                      >
                        <SelectTrigger
                          id={field.name}
                          aria-invalid={
                            field.state.meta.isTouched &&
                            !field.state.meta.isValid
                          }
                        >
                          <SelectValue placeholder="เลือกประเภทการอบรม" />
                        </SelectTrigger>
                        <SelectContent>
                          {trainingTypeOptions.map((option) => (
                            <SelectItem key={option.value} value={option.value}>
                              {option.label}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    </field.Field>
                    <field.FieldError />
                  </field.FieldSet>
                )}
              </form.AppField>

              <form.AppField
                name="submittedMinutes"
                validators={{
                  onBlur: z
                    .number({ message: "กรุณาระบุจำนวนชั่วโมงอบรม" })
                    .gt(0, "จำนวนชั่วโมงอบรมต้องมากกว่า 0 นาที")
                    .max(1800, "จำนวนชั่วโมงอบรมต้องไม่เกิน 30 ชั่วโมง"),
                }}
              >
                {(field) => (
                  <field.FieldSet>
                    <field.Field>
                      <field.FieldLabel htmlFor={field.name}>
                        จำนวนชั่วโมงอบรม *
                      </field.FieldLabel>
                      <div className="space-y-2">
                        <DurationPicker
                          valueMinutes={field.state.value ?? null}
                          onChange={(minutes) =>
                            field.handleChange(minutes ?? undefined)
                          }
                          maxHours={30}
                          minuteStep={5}
                          disabled={isSubmitting || !canManageRecord}
                        />
                        <div className="text-muted-foreground text-sm">
                          เลือกระยะเวลาอบรมเป็นชั่วโมงและนาที
                        </div>
                      </div>
                    </field.Field>
                    <field.FieldError />
                  </field.FieldSet>
                )}
              </form.AppField>

              <form.AppField name="organizer">
                {(field) => (
                  <field.FieldSet>
                    <field.Field>
                      <field.FieldLabel htmlFor={field.name}>
                        ผู้จัดอบรม/สถาบันอบรม
                      </field.FieldLabel>
                      <Input
                        id={field.name}
                        value={field.state.value ?? ""}
                        placeholder="กรอกชื่อสถาบันอบรม"
                        disabled={isSubmitting || !canManageRecord}
                        onBlur={field.handleBlur}
                        onChange={(event) =>
                          field.handleChange(event.target.value)
                        }
                      />
                    </field.Field>
                    <field.FieldError />
                  </field.FieldSet>
                )}
              </form.AppField>
            </div>

            <form.AppField name="note">
              {(field) => (
                <field.FieldSet>
                  <field.Field>
                    <field.FieldLabel htmlFor={field.name}>
                      หมายเหตุ
                    </field.FieldLabel>
                    <textarea
                      id={field.name}
                      aria-label="หมายเหตุ"
                      value={field.state.value ?? ""}
                      placeholder="เพิ่มหมายเหตุหรือสรุปการเรียนรู้"
                      maxLength={1000}
                      rows={5}
                      disabled={isSubmitting || !canManageRecord}
                      onBlur={field.handleBlur}
                      onChange={(event) =>
                        field.handleChange(event.target.value)
                      }
                      className="border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex min-h-[120px] w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
                    />
                  </field.Field>
                  <field.FieldError />
                </field.FieldSet>
              )}
            </form.AppField>

            {canManageRecord ? (
              <div className="space-y-3">
                <div>
                  <div className="text-sm font-medium">เพิ่มไฟล์แนบ</div>
                  <div className="text-muted-foreground text-sm">
                    รองรับไฟล์ PDF, JPG, JPEG และ PNG โดยระบบจะผูกไฟล์หลังจากบันทึกรายการอบรมแล้ว
                  </div>
                </div>
                <form.Subscribe selector={(state) => state.values.trainingType}>
                  {(trainingType) =>
                    isPublicTrainingType(trainingType) ? (
                      <div className="text-destructive text-sm">
                        {publicTrainingAttachmentNotice}
                      </div>
                    ) : null
                  }
                </form.Subscribe>
                <FileUploader
                  value={pendingFiles}
                  onValueChange={(files) => {
                    setPendingFiles(files);
                    if (files.length > 0 || existingCertificateCount > 0) {
                      setAttachmentError(null);
                    }
                  }}
                  accept={trainingRecordCertificateAccept}
                  maxSize={trainingRecordCertificateMaxSize}
                  maxFiles={trainingRecordCertificateMaxFiles}
                  multiple
                  showFileList={false}
                  disabled={isSubmitting || !canManageRecord}
                />
                {attachmentError ? (
                  <div className="text-destructive text-sm">{attachmentError}</div>
                ) : null}
              </div>
            ) : null}

            <TrainingRecordAttachmentList items={attachmentItems} />

            <div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
              <Button
                type="button"
                variant="outline"
                onClick={() => router.back()}
                className="w-full sm:w-auto"
              >
                กลับ
              </Button>
              <Button
                type="button"
                variant="secondary"
                disabled={isSubmitting || !canManageRecord}
                onClick={() => submitWithMode("draft")}
                className="w-full shrink-0 whitespace-nowrap sm:w-auto"
              >
                บันทึกฉบับร่าง
              </Button>
              <Button
                type="button"
                disabled={isSubmitting || !canManageRecord}
                onClick={() => submitWithMode("submit")}
                className="w-full shrink-0 whitespace-nowrap sm:w-auto"
              >
                {isSubmitting
                  ? getPendingLabel(isEdit, submitModeRef.current)
                  : primaryActionLabel}
              </Button>
            </div>
          </form.Form>
        </form.AppForm>
      </CardContent>
    </Card>
  );
}
