"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { useForm, Controller } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import {
  Calendar,
  ChevronDown,
  ChevronLeft,
  ChevronRight,
  Clock,
} from "lucide-react";

import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
} from "@/components/ui/select";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import {
  buildCalendarDays,
  formatMonthYear,
  formatSelectedDate,
  formatTimeDisplay,
  getWeekdayLabels,
} from "@/lib/calendar-locale";
import { isArmenianLocale, localeBodyClass } from "@/lib/locale-fonts";
import { submitDemoBooking } from "@/services/api/demo";

const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
// "+" is only allowed as the very first character; digits and spaces anywhere after.
const PHONE_PATTERN = /^\+?[\d\s]+$/;

function sanitizePhoneInput(value) {
  const hasLeadingPlus = value.startsWith("+");
  const digitsAndSpaces = value.replace(/\+/g, "").replace(/[^\d\s]/g, "");
  return hasLeadingPlus ? `+${digitsAndSpaces}` : digitsAndSpaces;
}

const HOURS = Array.from({ length: 24 }, (_, index) =>
  String(index).padStart(2, "0"),
);
const MINUTES = Array.from({ length: 60 }, (_, index) =>
  String(index).padStart(2, "0"),
);

function getField(items, name) {
  return items.find((item) => item.name === name) ?? null;
}

function getTomorrow() {
  const tomorrow = new Date();
  tomorrow.setDate(tomorrow.getDate() + 1);
  return tomorrow;
}

function getMonthStart(date) {
  return new Date(date.getFullYear(), date.getMonth(), 1);
}
function normalizeOptions(options) {
  return (options ?? []).map((option) =>
    typeof option === "string" ? { label: option, value: option } : option,
  );
}

function FormSelect({
  label,
  required,
  value,
  onChange,
  options,
  placeholder,
  variant = "bordered", // "bordered" | "pill"
  error,
  className = "",
}) {
  const [open, setOpen] = useState(false);
  const normalized = useMemo(() => normalizeOptions(options), [options]);
  const selectedLabel = normalized.find((opt) => opt.value === value)?.label;

  return (
    <div className="flex flex-col gap-1.5">
      {label ? (
        <span className="text-sm text-neutral-500">
          {label}
          {required ? " *" : ""}
        </span>
      ) : null}
      <Select
        value={value}
        onValueChange={onChange}
        open={open}
        onOpenChange={setOpen}
      >
        <SelectTrigger
          className={cn(
            "h-12 w-full bg-white px-4 text-sm text-[#3E4155] shadow-none focus:ring-0",
            variant === "pill"
              ? "rounded-full"
              : "rounded-2xl border border-[#C5C9D6]",
            error && "border-destructive",
            className,
          )}
        >
          <span className={cn(!selectedLabel && "text-neutral-400")}>
            {selectedLabel || placeholder}
          </span>
          <ChevronDown
            className={cn(
              "h-5 w-5 shrink-0 text-[#3E4155] transition-transform duration-200",
              open && "rotate-180",
            )}
          />
        </SelectTrigger>
        <SelectContent className="rounded-2xl bg-white p-1 shadow-lg">
          {normalized.map((option) => (
            <SelectItem
              key={option.value}
              value={option.value}
              className="hover:bg-primary focus:bg-primary cursor-pointer rounded-xl py-2.5 text-sm text-[#3E4155] focus:text-white"
            >
              {option.label}
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
      {error && (
        <p className="text-destructive text-xs" role="alert">
          {error}
        </p>
      )}
    </div>
  );
}

function FormInput({
  label,
  required,
  value,
  onChange,
  placeholder,
  type = "text",
  error,
}) {
  return (
    <div className="flex flex-col gap-1.5">
      <label className="text-sm text-neutral-500">
        {label}
        {required ? " *" : ""}
      </label>
      <input
        type={type}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        aria-invalid={!!error}
        className={cn(
          "focus:border-primaryPurple-400 h-12 w-full rounded-2xl border bg-white px-4 text-sm text-[#3E4155] outline-none placeholder:text-neutral-400",
          error ? "border-destructive" : "border-[#C5C9D6]",
        )}
      />
      {error && (
        <p className="text-destructive text-xs" role="alert">
          {error}
        </p>
      )}
    </div>
  );
}

function TimePicker({
  locale,
  value,
  onChange,
  placeholder,
  hourLabel,
  minuteLabel,
  error,
}) {
  const rootRef = useRef(null);
  const [open, setOpen] = useState(false);
  const [hour, minute] = value ? value.split(":") : ["", ""];
  const displayValue = formatTimeDisplay(value, locale);

  useEffect(() => {
    if (!open) return;

    const handleClickOutside = (event) => {
      if (rootRef.current && !rootRef.current.contains(event.target)) {
        setOpen(false);
      }
    };

    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, [open]);

  const updateTime = (nextHour, nextMinute) => {
    if (nextHour !== "" && nextMinute !== "") {
      onChange(`${nextHour}:${nextMinute}`);
    }
  };

  return (
    <div ref={rootRef} className="relative">
      <button
        type="button"
        onClick={() => setOpen((prev) => !prev)}
        className={cn(
          "flex h-12 w-full items-center justify-between rounded-2xl border bg-white px-4 text-sm transition-colors",
          error
            ? "border-destructive"
            : open
              ? "border-primaryPurple-400 ring-primaryPurple-100 ring-2"
              : "hover:border-primaryPurple-300 border-[#C5C9D6]",
        )}
      >
        <span className="flex min-w-0 items-center gap-3">
          <Clock className="text-primaryPurple-400 h-5 w-5 shrink-0" />
          <span
            className={cn(
              "truncate tabular-nums",
              displayValue ? "font-medium text-[#3E4155]" : "text-neutral-400",
            )}
          >
            {displayValue || placeholder}
          </span>
        </span>
        <ChevronDown
          className={cn(
            "h-5 w-5 shrink-0 text-[#3E4155] transition-transform duration-200",
            open && "rotate-180",
          )}
        />
      </button>

      {open && (
        <div className="absolute top-full right-0 left-0 z-20 mt-2 overflow-hidden rounded-2xl border border-[#E5E7EF] bg-white shadow-[0_8px_30px_rgba(62,65,85,0.12)]">
          <div className="grid grid-cols-2 divide-x divide-[#E5E7EF]">
            <div className="flex flex-col">
              <p className="text-primaryPurple-500 border-b border-[#E5E7EF] bg-[#FAFAFC] px-4 py-2.5 text-xs font-semibold tracking-wide uppercase">
                {hourLabel}
              </p>
              <ul className="max-h-48 [scrollbar-width:thin] [scrollbar-color:var(--primaryPurple-200)_transparent] overflow-y-auto py-2">
                {HOURS.map((item) => {
                  const active = hour === item;
                  return (
                    <li key={item}>
                      <button
                        type="button"
                        onClick={() => updateTime(item, minute || "00")}
                        className={cn(
                          "mx-2 w-[calc(100%-1rem)] rounded-xl px-3 py-2.5 text-center text-sm tabular-nums transition-colors",
                          active
                            ? "bg-primaryPurple-400 font-semibold text-white shadow-sm"
                            : "hover:bg-primaryPurple-100 text-[#3E4155]",
                        )}
                      >
                        {item}
                      </button>
                    </li>
                  );
                })}
              </ul>
            </div>

            <div className="flex flex-col">
              <p className="text-primaryPurple-500 border-b border-[#E5E7EF] bg-[#FAFAFC] px-4 py-2.5 text-xs font-semibold tracking-wide uppercase">
                {minuteLabel}
              </p>
              <ul className="max-h-48 [scrollbar-width:thin] [scrollbar-color:var(--primaryPurple-200)_transparent] overflow-y-auto py-2">
                {MINUTES.map((item) => {
                  const active = minute === item;
                  return (
                    <li key={item}>
                      <button
                        type="button"
                        onClick={() => {
                          updateTime(hour || "09", item);
                          setOpen(false);
                        }}
                        className={cn(
                          "mx-2 w-[calc(100%-1rem)] rounded-xl px-3 py-2.5 text-center text-sm tabular-nums transition-colors",
                          active
                            ? "bg-primaryPurple-400 font-semibold text-white shadow-sm"
                            : "hover:bg-primaryPurple-100 text-[#3E4155]",
                        )}
                      >
                        {item}
                      </button>
                    </li>
                  );
                })}
              </ul>
            </div>
          </div>
        </div>
      )}
      {error && (
        <p className="text-destructive mt-1.5 text-xs" role="alert">
          {error}
        </p>
      )}
    </div>
  );
}

function BookingCalendar({
  locale,
  month,
  selectedDate,
  onSelectDate,
  onMonthChange,
  prevMonthLabel,
  nextMonthLabel,
  calendarLabels,
}) {
  const isHy = isArmenianLocale(locale);

  const { days, monthLabel, weekdayLabels } = useMemo(() => {
    const year = month.getFullYear();
    const monthIndex = month.getMonth();

    return {
      days: buildCalendarDays(year, monthIndex, locale),
      monthLabel: formatMonthYear(month, locale, calendarLabels),
      weekdayLabels: getWeekdayLabels(locale, calendarLabels),
    };
  }, [calendarLabels, locale, month]);

  const isSameDay = (a, b) =>
    a &&
    b &&
    a.getFullYear() === b.getFullYear() &&
    a.getMonth() === b.getMonth() &&
    a.getDate() === b.getDate();

  return (
    <div
      lang={isHy ? "hy-AM" : locale}
      className={cn(
        "rounded-2xl border border-[#E5E7EF] bg-white p-4 shadow-sm",
        isHy && localeBodyClass(locale),
      )}
    >
      <div className="bg-primaryPurple-100 mb-4 flex items-center justify-between rounded-2xl px-2 py-2">
        <button
          type="button"
          onClick={() =>
            onMonthChange(
              new Date(month.getFullYear(), month.getMonth() - 1, 1),
            )
          }
          className="bg-primaryPurple-400 flex h-8 w-8 items-center justify-center rounded-full text-white"
          aria-label={prevMonthLabel}
        >
          <ChevronLeft className="h-4 w-4" />
        </button>
        <span
          className={cn(
            "text-primaryPurple-600 text-sm font-semibold tracking-wide",
            !isHy && "capitalize",
          )}
        >
          {monthLabel}
        </span>
        <button
          type="button"
          onClick={() =>
            onMonthChange(
              new Date(month.getFullYear(), month.getMonth() + 1, 1),
            )
          }
          className="bg-primaryPurple-400 flex h-8 w-8 items-center justify-center rounded-full text-white"
          aria-label={nextMonthLabel}
        >
          <ChevronRight className="h-4 w-4" />
        </button>
      </div>

      <div className="text-primaryPurple-500 grid grid-cols-7 gap-1 text-center text-xs font-semibold">
        {weekdayLabels.map((day, index) => (
          <span key={index} className="py-1">
            {day}
          </span>
        ))}
      </div>

      <div className="mt-1 grid grid-cols-7 gap-1">
        {days.map((date, index) => {
          if (!date) {
            return <span key={`empty-${index}`} />;
          }

          const selected = isSameDay(date, selectedDate);

          return (
            <button
              key={date.toISOString()}
              type="button"
              onClick={() => onSelectDate(date)}
              className={cn(
                "mx-auto flex h-8 w-8 items-center justify-center rounded-full text-sm transition-colors",
                selected
                  ? "bg-primaryPurple-400 font-semibold text-white"
                  : "text-primaryPurple-500 hover:bg-primaryPurple-100",
              )}
            >
              {date.getDate()}
            </button>
          );
        })}
      </div>
    </div>
  );
}

export default function BookADemoFormClient({
  locale,
  t,
  businessTypeOptions = [],
  className = "",
  showDemoType = true,
}) {
  "use no memo";

  const [submitState, setSubmitState] = useState("idle"); // "idle" | "submitting" | "success" | "error"
  const [dayTab, setDayTab] = useState("tomorrow");
  const [calendarMonth, setCalendarMonth] = useState(() =>
    getMonthStart(getTomorrow()),
  );
  const [showCalendar, setShowCalendar] = useState(false);

  const fields = useMemo(
    () =>
      t.items.reduce((acc, field) => {
        acc[field.name] = field;
        return acc;
      }, {}),
    [t.items],
  );

  const demoTypeOptions = useMemo(
    () => normalizeOptions(fields.demoType?.options),
    [fields.demoType],
  );

  const calendarLabels = isArmenianLocale(locale) ? t.schedule.calendar : null;

  const schema = useMemo(
    () =>
      z
        .object({
          demoType: z.string().min(1, t.feedback.required),
          businessType: z.string().min(1, t.feedback.required),
          name: z.string().min(1, t.feedback.required),
          email: z.string().min(1, t.feedback.required),
          businessName: z.string().min(1, t.feedback.required),
          phone: z.string().min(1, t.feedback.required),
          selectedDate: z.date(),
          selectedTime: z.string().min(1, t.feedback.datetimeRequired),
        })
        .superRefine((data, ctx) => {
          if (data.email && !EMAIL_PATTERN.test(data.email)) {
            ctx.addIssue({
              code: z.ZodIssueCode.custom,
              message: t.feedback.invalidEmail,
              path: ["email"],
            });
          }
          if (data.phone && !PHONE_PATTERN.test(data.phone)) {
            ctx.addIssue({
              code: z.ZodIssueCode.custom,
              message: t.feedback.invalidPhone ?? t.feedback.required,
              path: ["phone"],
            });
          }
        }),
    [t.feedback],
  );

  const {
    control,
    handleSubmit,
    watch,
    setValue,
    reset,
    formState: { errors, isSubmitting },
  } = useForm({
    resolver: zodResolver(schema),
    defaultValues: {
      demoType: "",
      businessType: "",
      name: "",
      email: "",
      businessName: "",
      phone: "",
      selectedDate: getTomorrow(),
      selectedTime: "",
    },
  });

  const selectedDate = watch("selectedDate");
  const selectedTime = watch("selectedTime");

  const formattedDate = selectedDate
    ? formatSelectedDate(selectedDate, locale, calendarLabels)
    : "";

  const handleDayTab = (tab) => {
    setDayTab(tab);
    const base = new Date();
    if (tab === "tomorrow") {
      base.setDate(base.getDate() + 1);
    }
    setValue("selectedDate", base, { shouldValidate: false });
    setCalendarMonth(getMonthStart(base));
    setShowCalendar(true);
  };

  const onSubmit = async (values) => {
    setSubmitState("submitting");
    try {
      await submitDemoBooking(values);
      setSubmitState("success");
      reset({
        demoType: "",
        businessType: "",
        name: "",
        email: "",
        businessName: "",
        phone: "",
        selectedDate: getTomorrow(),
        selectedTime: "",
      });
      setDayTab("tomorrow");
      setShowCalendar(false);
    } catch (error) {
      console.error("Demo booking submission failed:", error);
      setSubmitState("error");
    }
  };

  return (
    <section
      className={cn(
        "bg-primary-foreground px-5 py-10 md:py-16 lg:px-20 xl:px-45",
        className,
      )}
    >
      <form
        onSubmit={handleSubmit(onSubmit)}
        noValidate
        className="mx-auto max-w-6xl"
      >
        {showDemoType && (
          <div className="w-1/3">
            <Controller
              control={control}
              name="demoType"
              render={({ field }) => (
                <FormSelect
                  variant="pill"
                  placeholder={fields.demoType?.label}
                  value={field.value}
                  onChange={field.onChange}
                  options={demoTypeOptions}
                  error={errors.demoType?.message}
                />
              )}
            />
          </div>
        )}

        {(submitState === "success" || submitState === "error") && (
          <div
            role="alert"
            className={cn(
              "mt-6 rounded-2xl border px-4 py-3 text-sm",
              submitState === "success"
                ? "border-green-200 bg-green-50 text-green-800"
                : "border-red-200 bg-red-50 text-red-800",
            )}
          >
            {submitState === "success" ? t.feedback.success : t.feedback.error}
          </div>
        )}

        <div className="mt-8 grid grid-cols-1 gap-8 lg:grid-cols-2 lg:gap-12">
          <div className="flex flex-col gap-5">
            <Controller
              control={control}
              name="name"
              render={({ field }) => (
                <FormInput
                  label={fields.name?.label}
                  required={fields.name?.required}
                  value={field.value}
                  onChange={field.onChange}
                  placeholder={t.placeholders.name}
                  error={errors.name?.message}
                />
              )}
            />

            <Controller
              control={control}
              name="businessType"
              render={({ field }) => (
                <FormSelect
                  label={fields.businessType?.label}
                  required
                  placeholder={fields.businessType?.label}
                  value={field.value}
                  onChange={field.onChange}
                  options={businessTypeOptions}
                  error={errors.businessType?.message}
                  className="rounded-full"
                />
              )}
            />

            <Controller
              control={control}
              name="email"
              render={({ field }) => (
                <FormInput
                  label={fields.email?.label}
                  required={fields.email?.required}
                  type="email"
                  value={field.value}
                  onChange={field.onChange}
                  placeholder={t.placeholders.email}
                  error={errors.email?.message}
                />
              )}
            />

            <Controller
              control={control}
              name="businessName"
              render={({ field }) => (
                <FormInput
                  label={fields.businessName?.label}
                  required={fields.businessName?.required}
                  value={field.value}
                  onChange={field.onChange}
                  placeholder={t.placeholders.businessName}
                  error={errors.businessName?.message}
                />
              )}
            />

            <Controller
              control={control}
              name="phone"
              render={({ field }) => (
                <FormInput
                  label={fields.phone?.label}
                  required={fields.phone?.required}
                  type="tel"
                  value={field.value}
                  onChange={(value) =>
                    field.onChange(sanitizePhoneInput(value))
                  }
                  placeholder={t.placeholders.phone}
                  error={errors.phone?.message}
                />
              )}
            />

            <Button
              type="submit"
              disabled={isSubmitting}
              className="bg-primaryPurple-400 hover:bg-primaryPurple-500 mt-2 h-12 w-fit rounded-full px-10 text-sm font-bold tracking-wider text-white uppercase"
            >
              {isSubmitting ? "..." : t.submit}
            </Button>
          </div>

          <div className="flex flex-col gap-5">
            <h3 className="text-lg font-bold text-neutral-700">
              {t.schedule.title}
            </h3>

            <div className="grid grid-cols-2 gap-3">
              <button
                type="button"
                onClick={() => handleDayTab("today")}
                className={cn(
                  "h-12 rounded-2xl border text-sm font-semibold transition-colors",
                  dayTab === "today"
                    ? "border-primaryPurple-400 bg-primaryPurple-400 text-white"
                    : "border-[#C5C9D6] bg-white text-neutral-500",
                )}
              >
                {t.schedule.today}
              </button>
              <button
                type="button"
                onClick={() => handleDayTab("tomorrow")}
                className={cn(
                  "h-12 rounded-2xl border text-sm font-semibold transition-colors",
                  dayTab === "tomorrow"
                    ? "border-primaryPurple-400 bg-primaryPurple-400 text-white"
                    : "border-[#C5C9D6] bg-white text-neutral-500",
                )}
              >
                {t.schedule.tomorrow}
              </button>
            </div>

            <div className="grid grid-cols-2 gap-3">
              <button
                type="button"
                onClick={() => setShowCalendar((prev) => !prev)}
                className={cn(
                  "flex h-12 w-full items-center gap-3 rounded-2xl border bg-white px-4 text-left text-sm text-neutral-500 transition-colors",
                  showCalendar
                    ? "border-primaryPurple-400 ring-primaryPurple-100 ring-2"
                    : "hover:border-primaryPurple-300 border-[#C5C9D6]",
                )}
              >
                <Calendar className="text-primaryPurple-400 h-5 w-5 shrink-0" />
                <span
                  className={cn("truncate", formattedDate && "text-[#3E4155]")}
                >
                  {formattedDate || t.schedule.chooseDay}
                </span>
              </button>

              <TimePicker
                locale={locale}
                value={selectedTime}
                onChange={(time) =>
                  setValue("selectedTime", time, { shouldValidate: true })
                }
                placeholder={t.schedule.chooseTime}
                hourLabel={t.schedule.hour}
                minuteLabel={t.schedule.minute}
                error={errors.selectedTime?.message}
              />
            </div>

            {showCalendar && (
              <BookingCalendar
                locale={locale}
                month={calendarMonth}
                selectedDate={selectedDate}
                onSelectDate={(date) => {
                  setValue("selectedDate", date, { shouldValidate: false });
                  setShowCalendar(false);
                }}
                onMonthChange={setCalendarMonth}
                prevMonthLabel={t.schedule.prevMonth}
                nextMonthLabel={t.schedule.nextMonth}
                calendarLabels={calendarLabels}
              />
            )}
          </div>
        </div>
      </form>
    </section>
  );
}
