import { Button, Flex, Group, Stack, Tabs, Text } from "@mantine/core";
import { useEffect, useState } from "react";
import { useForm, type FieldErrors } from "react-hook-form";
import { useFetcher, useNavigate } from "react-router";
import {
  type CreateBookingFormData,
  type CreateBookingGuest,
  type CreateBookingCharge,
  type ChargeType,
  CHARGE_DEFAULT_CURRENCY,
  CHARGE_NAME_BY_TYPE,
  CHARGE_TYPE_ORDER,
  DEFAULT_UNIT_CHARGES,
} from "@/lib/features/bookings/createBooking.types";

import MemberSection from "./sections/memberSection";
import UnitSection from "./sections/unitSection";
import PaymentSection from "./sections/paymentSection";

type ActionResponse = {
  success: boolean;
  message?: string;
  data?: any;
};

const DEFAULT_GUEST: CreateBookingGuest = {
  contactID: "",
  isPrimaryGuest: true,
  type: "OWNER" as const,
  sendBookingConfirmation: true,
  additional_data: {
    special_requests: "NA",
    has_travel_insurance: "true",
    is_pet_travelling: "false",
    medical_mobility_requirements: "None",
  },
};

const normalizeCharges = (charges: CreateBookingCharge[] = []) => {
  const sanitized = (charges || []).map((charge) => {
    const type = (charge.type || "ADDITIONAL_CHARGE") as ChargeType;
    return {
      value: Number(charge.value ?? 0),
      type,
      currency: charge.currency ?? CHARGE_DEFAULT_CURRENCY[type],
      name: charge.name?.trim() || CHARGE_NAME_BY_TYPE[type],
    };
  });

  const ordered: CreateBookingCharge[] = [];
  CHARGE_TYPE_ORDER.forEach((type) => {
    const matched = sanitized.filter((charge) => charge.type === type);
    if (matched.length > 0) {
      ordered.push(...matched);
    } else {
      ordered.push({
        type,
        value: 0,
        currency: CHARGE_DEFAULT_CURRENCY[type],
        name: CHARGE_NAME_BY_TYPE[type],
      });
    }
  });

  return ordered;
};

type TabValue = "member" | "units" | "payment";

const CreateBookingForm: React.FC = () => {
  const navigate = useNavigate();
  const fetcher = useFetcher<ActionResponse>();

  const [activeTab, setActiveTab] = useState<TabValue>("member");

  const {
    control,
    handleSubmit,
    formState: { errors, isValid },
    watch,
    setValue,
  } = useForm<CreateBookingFormData>({
    mode: "onChange",
    reValidateMode: "onChange",
    defaultValues: {
      memberRecordID: "",
      resort: {
        rciResortCode: "",
        additionalData: {
          partner: "RCI",
        },
      },
      inventoryType: "EXCHANGE",
      units: [
        {
          bedroom_type: "1 Bedroom",
          note: "",
          additionalData: {},
          guests: [{ ...DEFAULT_GUEST }],
          adults: 0,
          children: 0,
          infants: 0,
          externalBooking: {
            refID: "",
            additionalData: { channel: "RCI" },
          },
          checkInDate: "",
          checkOutDate: "",
          charges: DEFAULT_UNIT_CHARGES.map((charge) => ({ ...charge })),
        },
      ],
      bookedAt: new Date().toISOString(),
      bookingSource: "Admin Panel",
      note: "",
      additionalData: {},
      paymentDetails: {
        amount: 0,
        currency: "INR",
        ref_id: "",
        method_name: "CREDIT_CARD",
        gateway_name: "",
      },
    },
  });

  const isSubmitting = fetcher.state !== "idle";

  useEffect(() => {
    if (!fetcher.data) return;

    if (fetcher.data.success) {
      navigate("/admin/bookings?tab=external");
      return;
    }

    alert(fetcher.data.message || "Failed to create booking");
  }, [fetcher.data, navigate]);

  const normalizePayload = (
    data: CreateBookingFormData,
  ): CreateBookingFormData => {
    const normalizedUnits = (data.units || []).map((unit) => {
      const guests = (unit.guests || []).map((g) => ({
        contactID: String(g.contactID || ""),
        isPrimaryGuest: Boolean(g.isPrimaryGuest),
        type: g.type || "OWNER",
        sendBookingConfirmation: g.sendBookingConfirmation ?? true,
        additional_data: {
          special_requests: g.additional_data?.special_requests ?? "NA",
          has_travel_insurance:
            g.additional_data?.has_travel_insurance ?? "true",
          is_pet_travelling: g.additional_data?.is_pet_travelling ?? "false",
          medical_mobility_requirements:
            g.additional_data?.medical_mobility_requirements ?? "None",
        },
      }));

      const primaryIdx = guests.findIndex((g) => g.isPrimaryGuest);
      if (guests.length > 0) {
        if (primaryIdx === -1) {
          guests[0].isPrimaryGuest = true;
        } else {
          guests.forEach((g, idx) => (g.isPrimaryGuest = idx === primaryIdx));
        }
      }

      const charges = normalizeCharges(unit.charges);

      return {
        ...unit,
        bedroom_type: unit.bedroom_type || "1 Bedroom",
        additionalData: unit.additionalData ?? {},
        guests,
        adults: Number(unit.adults ?? 0),
        children: Number(unit.children ?? 0),
        infants: Number(unit.infants ?? 0),
        externalBooking: {
          refID: unit.externalBooking?.refID || "",
          additionalData: {
            channel: unit.externalBooking?.additionalData?.channel ?? "RCI",
            ...(unit.externalBooking?.additionalData ?? {}),
          },
        },
        charges,
      };
    });

    return {
      ...data,
      bookedAt: data.bookedAt || new Date().toISOString(),
      bookingSource: data.bookingSource || "Admin Panel",
      note: data.note ?? "",
      additionalData: data.additionalData ?? {},
      resort: {
        rciResortCode: data.resort?.rciResortCode || "",
        additionalData: {
          partner: data.resort?.additionalData?.partner ?? "RCI",
        },
      },
      inventoryType: data.inventoryType || "EXCHANGE",
      units: normalizedUnits,
      paymentDetails: {
        amount: Number(data.paymentDetails?.amount ?? 0),
        currency: data.paymentDetails?.currency ?? "INR",
        ref_id: data.paymentDetails?.ref_id ?? "",
        method_name: data.paymentDetails?.method_name ?? "CREDIT_CARD",
        gateway_name: data.paymentDetails?.gateway_name ?? "",
      },
    };
  };

  const validateBeforeSubmit = (payload: CreateBookingFormData) => {
    for (let i = 0; i < payload.units.length; i++) {
      const unit = payload.units[i];
      if (!unit.guests || unit.guests.length === 0) {
        setActiveTab("units");
        throw new Error(`Unit ${i + 1}: Please add at least one guest.`);
      }

      const invalidGuest = unit.guests.find(
        (g) => !String(g.contactID || "").trim(),
      );
      if (invalidGuest) {
        setActiveTab("units");
        throw new Error(`Unit ${i + 1}: Guest contactID is required.`);
      }
    }
  };

  const determineErrorTab = (
    formErrors: FieldErrors<CreateBookingFormData>,
  ): TabValue | null => {
    if (
      formErrors.memberRecordID ||
      formErrors.resort?.rciResortCode ||
      formErrors.resort?.additionalData?.partner ||
      formErrors.inventoryType
    ) {
      return "member";
    }

    if (formErrors.units && Object.keys(formErrors.units).length > 0) {
      return "units";
    }

    if (
      formErrors.paymentDetails &&
      Object.keys(formErrors.paymentDetails).length > 0
    ) {
      return "payment";
    }

    return null;
  };

  const handleFormErrors = (formErrors: FieldErrors<CreateBookingFormData>) => {
    const tab = determineErrorTab(formErrors);
    if (tab) {
      setActiveTab(tab);
    }
  };

  const onSubmit = (data: CreateBookingFormData) => {
    try {
      const payload = normalizePayload(data);
      validateBeforeSubmit(payload);
      fetcher.submit({ payload: JSON.stringify(payload) }, { method: "post" });
    } catch (e) {
      alert(e instanceof Error ? e.message : "Invalid form data");
    }
  };

  const handleCancel = () => {
    navigate("/admin/bookings?tab=external");
  };

  return (
    <form onSubmit={handleSubmit(onSubmit, handleFormErrors)}>
      <Stack gap="lg" p="lg" m="lg">
        <Flex justify={"space-between"} align={"center"} mb="lg">
          <div>
            <Text fz={24} fw={700}>
              Create Booking
            </Text>
            <Text fz={14} c="dimmed">
              Fill in the booking details step by step
            </Text>
          </div>
        </Flex>

        <Tabs
          value={activeTab}
          onChange={(value) => {
            if (value) setActiveTab(value as TabValue);
          }}
        >
          <Tabs.List>
            <Tabs.Tab value="member">Member & Resort</Tabs.Tab>
            <Tabs.Tab value="units">Units</Tabs.Tab>
            <Tabs.Tab value="payment">Payment</Tabs.Tab>
          </Tabs.List>

          <Tabs.Panel value="member" pt="lg">
            <MemberSection control={control} errors={errors} />
          </Tabs.Panel>

          <Tabs.Panel value="units" pt="lg">
            <UnitSection
              control={control}
              errors={errors}
              watch={watch}
              setValue={setValue}
            />
          </Tabs.Panel>

          <Tabs.Panel value="payment" pt="lg">
            <PaymentSection control={control} errors={errors} watch={watch} />
          </Tabs.Panel>
        </Tabs>

        <Group justify="flex-end" mt="xl">
          <Button
            variant="default"
            onClick={handleCancel}
            disabled={isSubmitting}
          >
            Cancel
          </Button>
          <Button
            type="submit"
            loading={isSubmitting}
            disabled={!isValid || isSubmitting}
          >
            Create Booking
          </Button>
        </Group>
      </Stack>
    </form>
  );
};

export default CreateBookingForm;
