"use client";

import * as React from "react";
import Image from "next/image";
import { useForm, Controller, type Resolver } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Checkbox } from "@/components/ui/checkbox";
import {
  Dialog,
  DialogContent,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import {
  Field,
  FieldContent,
  FieldLabel,
  FieldError,
} from "@/components/ui/field";
import { Loader2, Upload, X, UserCircle2 } from "lucide-react";
import { toast } from "sonner";
import { apiBaseUrl, getFileUrl } from "@/api/client";
import { useAuthToken } from "@/hooks/use-auth-token";
import {
  useCreateCustomerContactMutation,
  useUpdateCustomerContactMutation,
  type CustomerAccountContactRecord,
} from "@/api/rtk/customer-contacts-api";

export interface CustomerContactDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  customerId: string;
  contact: CustomerAccountContactRecord | null;
}

type FormValues = {
  name: string;
  email: string;
  phone: string;
  title: string;
  department: string;
  notes: string;
  isPrimary: boolean;
};

function createContactSchema(isCreate: boolean) {
  return yup.object({
    name: yup
      .string()
      .trim()
      .required("Name is required")
      .max(200, "Name must be at most 200 characters"),
    email: isCreate
      ? yup
          .string()
          .trim()
          .required("Email is required")
          .email("Enter a valid email address")
          .max(320, "Email must be at most 320 characters")
      : yup
          .string()
          .trim()
          .max(320, "Email must be at most 320 characters")
          .test(
            "email-format",
            "Enter a valid email address",
            (v) => v === "" || yup.string().email().isValidSync(v),
          ),
    phone: isCreate
      ? yup
          .string()
          .trim()
          .required("Phone is required")
          .matches(/^[0-9]+$/, "Phone must contain only numbers")
          .max(64, "Phone must be at most 64 characters")
      : yup
          .string()
          .trim()
          .matches(/^[0-9]*$/, "Phone must contain only numbers")
          .max(64, "Phone must be at most 64 characters"),
    title: yup.string().trim().max(200).default(""),
    department: yup.string().trim().max(200).default(""),
    notes: yup.string().trim().max(2000).default(""),
    isPrimary: yup.boolean().default(false),
  });
}

const defaultFormValues: FormValues = {
  name: "",
  email: "",
  phone: "",
  title: "",
  department: "",
  notes: "",
  isPrimary: false,
};

export function CustomerContactDialog({
  open,
  onOpenChange,
  customerId,
  contact,
}: CustomerContactDialogProps) {
  const { token } = useAuthToken();
  const isEdit = Boolean(contact);
  const [selectedImage, setSelectedImage] = React.useState<File | null>(null);
  const [imagePreview, setImagePreview] = React.useState<string | null>(null);
  const [imageRemoved, setImageRemoved] = React.useState(false);

  const schema = React.useMemo(
    () => createContactSchema(!isEdit),
    [isEdit],
  );

  const {
    register,
    control,
    handleSubmit,
    reset,
    formState: { errors },
  } = useForm<FormValues>({
    resolver: yupResolver(schema) as Resolver<FormValues>,
    defaultValues: defaultFormValues,
    mode: "onTouched",
  });

  const [createContact, { isLoading: creating }] =
    useCreateCustomerContactMutation();
  const [updateContact, { isLoading: updating }] =
    useUpdateCustomerContactMutation();

  const saving = creating || updating;

  React.useEffect(() => {
    if (!open) return;
    setSelectedImage(null);
    setImagePreview(null);
    setImageRemoved(false);
    if (contact) {
      reset({
        name: contact.name,
        email: contact.email ?? "",
        phone: contact.phone ?? "",
        title: contact.title ?? "",
        department: contact.department ?? "",
        notes: contact.notes ?? "",
        isPrimary: contact.isPrimary,
      });
    } else {
      reset(defaultFormValues);
    }
  }, [open, contact, reset]);

  const handleImageSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (file) {
      if (file.size > 600 * 1024) {
        toast.error("Image size should be less than 600KB");
        return;
      }
      setSelectedImage(file);
      setImagePreview(URL.createObjectURL(file));
      setImageRemoved(false);
    }
  };

  const clearImage = () => {
    setSelectedImage(null);
    setImagePreview(null);
    setImageRemoved(true);
  };

  const onSubmit = async (values: FormValues) => {
    const n = values.name.trim();
    try {
      let avatarId = contact?.avatarId || null;

      if (selectedImage) {
        const formData = new FormData();
        formData.append("file", selectedImage);
        const uploadRes = await fetch(`${apiBaseUrl}/media/upload`, {
          method: "POST",
          headers: {
            Authorization: `Bearer ${token}`,
          },
          body: formData,
        });
        if (!uploadRes.ok) throw new Error("Failed to upload image");
        const res = await uploadRes.json();
        avatarId = res.data?.id || res.id;
      } else if (imageRemoved) {
        avatarId = null;
      }

      if (isEdit && contact) {
        await updateContact({
          customerId,
          contactId: contact.id,
          body: {
            name: n,
            email: values.email.trim() || null,
            phone: values.phone.trim() || null,
            title: values.title.trim() || null,
            department: values.department.trim() || null,
            notes: values.notes.trim() || null,
            isPrimary: values.isPrimary,
            avatarId,
          },
        }).unwrap();
        toast.success("Contact updated");
      } else {
        await createContact({
          customerId,
          body: {
            name: n,
            email: values.email.trim() || null,
            phone: values.phone.trim() || null,
            title: values.title.trim() || null,
            department: values.department.trim() || null,
            notes: values.notes.trim() || null,
            isPrimary: values.isPrimary,
            avatarId,
          },
        }).unwrap();
        toast.success("Contact added");
      }
      onOpenChange(false);
    } catch (err: unknown) {
      const msg =
        err &&
        typeof err === "object" &&
        "data" in err &&
        err.data &&
        typeof err.data === "object" &&
        "message" in err.data
          ? String((err.data as { message: unknown }).message)
          : "Could not save contact";
      toast.error(msg);
    }
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-md rounded-2xl">
        <DialogHeader>
          <DialogTitle className="font-['Lexend']">
            {isEdit ? "Edit contact" : "New customer contact"}
          </DialogTitle>
        </DialogHeader>
        <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
          {/* Avatar Upload */}
          <div className="flex flex-col items-center gap-4 py-2">
            <div className="relative group">
              <div className="relative size-20 rounded-2xl bg-gray-100 border-2 border-dashed border-gray-200 flex items-center justify-center overflow-hidden transition-all group-hover:border-[#6C63FF]/50">
                {imagePreview || (contact?.avatar?.url && !imageRemoved) ? (
                  <Image
                    src={
                      imagePreview || getFileUrl(contact?.avatar?.url) || ""
                    }
                    alt="Preview"
                    fill
                    sizes="80px"
                    className="object-cover"
                    unoptimized={
                      (imagePreview ?? "").startsWith("blob:") ||
                      (imagePreview ?? "").startsWith("data:")
                    }
                  />
                ) : (
                  <UserCircle2 size={32} className="text-gray-300" />
                )}
              </div>
              {(imagePreview || (contact?.avatar?.url && !imageRemoved)) && (
                <button
                  type="button"
                  onClick={clearImage}
                  className="absolute -top-2 -right-2 size-6 rounded-full bg-white border border-gray-200 shadow-sm flex items-center justify-center text-gray-400 hover:text-red-500 transition-colors"
                >
                  <X size={14} />
                </button>
              )}
            </div>
            <div className="flex flex-col items-center">
              <label
                htmlFor="cc-avatar-upload"
                className="inline-flex items-center gap-2 px-3 py-1.5 bg-gray-50 hover:bg-gray-100 border border-gray-200 rounded-xl cursor-pointer transition-colors text-[12px] font-medium text-gray-700"
              >
                <Upload size={13} />
                {selectedImage || contact?.avatar ? "Change photo" : "Upload photo"}
              </label>
              <input
                id="cc-avatar-upload"
                type="file"
                accept="image/*"
                className="hidden"
                onChange={handleImageSelect}
              />
              <p className="text-[10px] text-gray-400 mt-1.5">
                Optional: JPG, PNG or GIF. Max 600KB.
              </p>
            </div>
          </div>
          <Field data-invalid={!!errors.name}>
            <FieldLabel htmlFor="cc-name">Name *</FieldLabel>
            <FieldContent>
              <Input
                id="cc-name"
                placeholder="Full name"
                className="rounded-xl"
                aria-invalid={!!errors.name}
                {...register("name")}
              />
              <FieldError errors={[errors.name]} />
            </FieldContent>
          </Field>
          <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
            <Field data-invalid={!!errors.email}>
              <FieldLabel htmlFor="cc-email">
                Email{!isEdit ? " *" : ""}
              </FieldLabel>
              <FieldContent>
                <Input
                  id="cc-email"
                  type="email"
                  placeholder="email@company.com"
                  className="rounded-xl"
                  aria-invalid={!!errors.email}
                  {...register("email")}
                />
                <FieldError errors={[errors.email]} />
              </FieldContent>
            </Field>
            <Field data-invalid={!!errors.phone}>
              <FieldLabel htmlFor="cc-phone">
                Phone{!isEdit ? " *" : ""}
              </FieldLabel>
              <FieldContent>
                <Input
                  id="cc-phone"
                  placeholder="Phone"
                  className="rounded-xl"
                  aria-invalid={!!errors.phone}
                  {...register("phone")}
                  onInput={(e) => {
                    e.currentTarget.value = e.currentTarget.value.replace(/[^0-9]/g, "");
                  }}
                />
                <FieldError errors={[errors.phone]} />
              </FieldContent>
            </Field>
          </div>
          <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
            <Field data-invalid={!!errors.title}>
              <FieldLabel htmlFor="cc-title">Job title</FieldLabel>
              <FieldContent>
                <Input
                  id="cc-title"
                  placeholder="Title"
                  className="rounded-xl"
                  aria-invalid={!!errors.title}
                  {...register("title")}
                />
                <FieldError errors={[errors.title]} />
              </FieldContent>
            </Field>
            <Field data-invalid={!!errors.department}>
              <FieldLabel htmlFor="cc-dept">Department</FieldLabel>
              <FieldContent>
                <Input
                  id="cc-dept"
                  placeholder="Department"
                  className="rounded-xl"
                  aria-invalid={!!errors.department}
                  {...register("department")}
                />
                <FieldError errors={[errors.department]} />
              </FieldContent>
            </Field>
          </div>
          <Field data-invalid={!!errors.notes}>
            <FieldLabel htmlFor="cc-notes">Notes</FieldLabel>
            <FieldContent>
              <Textarea
                id="cc-notes"
                placeholder="Optional notes"
                rows={3}
                className="rounded-xl resize-none"
                aria-invalid={!!errors.notes}
                {...register("notes")}
              />
              <FieldError errors={[errors.notes]} />
            </FieldContent>
          </Field>
          <div className="flex items-center gap-2">
            <Controller
              name="isPrimary"
              control={control}
              render={({ field }) => (
                <Checkbox
                  id="cc-primary"
                  checked={field.value}
                  onCheckedChange={(v) => field.onChange(v === true)}
                />
              )}
            />
            <FieldLabel
              htmlFor="cc-primary"
              className="text-sm font-normal cursor-pointer"
            >
              Primary contact for this customer
            </FieldLabel>
          </div>
          <DialogFooter className="gap-2 sm:gap-3">
            <Button
              type="button"
              variant="outline"
              className="rounded-xl"
              onClick={() => onOpenChange(false)}
            >
              Cancel
            </Button>
            <Button
              type="submit"
              disabled={saving}
              className="rounded-xl bg-[#6C63FF] hover:bg-[#5a52e6]"
            >
              {saving ? (
                <>
                  <Loader2 className="size-4 animate-spin mr-2" />
                  Saving…
                </>
              ) : isEdit ? (
                "Save changes"
              ) : (
                "Add contact"
              )}
            </Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  );
}
