"use client";

import { useState, useEffect, useCallback } from "react";
import { Alert, Button, Card, Spinner } from "@heroui/react";

import { useAddressValidation, useAddressMutations } from "@/lib/checkout";
import type {
  CheckoutAddress,
  CheckoutAddressValidationResult,
  AddressFormData,
} from "@/lib/checkout/types";
import { AddressSelector } from "../content/AddressSelector";
import { AddressForm } from "../content/AddressForm";
import { AddressValidationFeedback } from "../content/AddressValidationFeedback";

type ShippingAddressStepProps = {
  addresses: CheckoutAddress[];
  isLoadingAddresses: boolean;
  onProceed: (selectedAddressId: string) => void;
  onBack: () => void;
};

type StepMode = "select" | "form" | "feedback";

export function ShippingAddressStep({
  addresses,
  isLoadingAddresses,
  onProceed,
  onBack,
}: ShippingAddressStepProps) {
  const { validate, isValidating, error: validationError, reset: resetValidation } = useAddressValidation();
  const { addAddress, markValidated } = useAddressMutations();

  const defaultAddr = addresses.find((a) => a.isDefault) ?? addresses[0];

  const [selectedId, setSelectedId] = useState<string | null>(defaultAddr?.id ?? null);
  const [mode, setMode] = useState<StepMode>(
    isLoadingAddresses || addresses.length > 0 ? "select" : "form",
  );
  const [formData, setFormData] = useState<AddressFormData | null>(null);
  const [validationResult, setValidationResult] = useState<CheckoutAddressValidationResult | null>(null);
  const [isSaving, setIsSaving] = useState(false);
  const [actionError, setActionError] = useState<string | null>(null);
  const [revalidatingAddressId, setRevalidatingAddressId] = useState<string | null>(null);
  const [shippoFailed, setShippoFailed] = useState(false);

  useEffect(() => {
    if (!isLoadingAddresses) {
      if (addresses.length > 0) {
        setMode((prev) => (prev === "form" && formData ? prev : "select"));
        if (!selectedId || !addresses.some((a) => a.id === selectedId)) {
          const def = addresses.find((a) => a.isDefault) ?? addresses[0];
          setSelectedId(def?.id ?? null);
        }
        if (revalidatingAddressId && !addresses.some((a) => a.id === revalidatingAddressId)) {
          setRevalidatingAddressId(null);
          setValidationResult(null);
          setMode("select");
        }
      } else if (mode === "select") {
        setMode("form");
      }
    }
  }, [addresses, isLoadingAddresses]); // eslint-disable-line react-hooks/exhaustive-deps

  const handleSelectAddress = useCallback((id: string) => {
    setSelectedId(id);
    setShippoFailed(false);
    setActionError(null);
  }, []);

  const handleContinue = useCallback(async () => {
    if (!selectedId) return;
    const addr = addresses.find((a) => a.id === selectedId);
    if (!addr) return;

    if (addr.isValidated) {
      onProceed(selectedId);
      return;
    }

    setActionError(null);
    setShippoFailed(false);
    const result = await validate({
      firstName: addr.firstName,
      lastName: addr.lastName,
      phone: addr.phone,
      addressLine1: addr.addressLine1,
      additionalInformation: addr.additionalInformation,
      city: addr.city,
      postalCode: addr.postalCode,
      country: addr.country,
    });

    if (result) {
      if (result.isValid && !result.recommendedAddress) {
        setIsSaving(true);
        try {
          await markValidated(selectedId, true);
          onProceed(selectedId);
        } catch {
          setActionError("Failed to update address. Please try again.");
        } finally {
          setIsSaving(false);
        }
        return;
      }

      setRevalidatingAddressId(selectedId);
      setFormData({
        firstName: addr.firstName,
        lastName: addr.lastName,
        phone: addr.phone,
        addressLine1: addr.addressLine1,
        additionalInformation: addr.additionalInformation,
        city: addr.city,
        postalCode: addr.postalCode,
        country: addr.country,
      });
      setValidationResult(result);
      setMode("feedback");
    } else {
      setActionError(
        "We couldn\u2019t verify your address right now. You can continue \u2014 we\u2019ll verify it later.",
      );
      setShippoFailed(true);
    }
  }, [selectedId, addresses, onProceed, validate, markValidated]);

  const handleFormSubmit = useCallback(
    async (data: AddressFormData) => {
      setFormData(data);
      setActionError(null);
      setShippoFailed(false);
      const result = await validate(data);

      if (result) {
        setRevalidatingAddressId(null);
        setValidationResult(result);
        setMode("feedback");
      } else {
        setShippoFailed(true);
      }
    },
    [validate],
  );

  const handleSaveWithoutValidation = useCallback(async () => {
    if (selectedId && mode === "select") {
      onProceed(selectedId);
      return;
    }

    if (!formData) return;
    setIsSaving(true);
    setActionError(null);

    try {
      const newId = await addAddress({
        ...formData,
        isValidated: false,
      });
      setSelectedId(newId);
      onProceed(newId);
    } catch {
      setActionError("Failed to save address. Please try again.");
    } finally {
      setIsSaving(false);
    }
  }, [selectedId, mode, formData, addAddress, onProceed]);

  const handleAcceptRecommended = useCallback(async () => {
    if (!validationResult?.recommendedAddress) return;
    const rec = validationResult.recommendedAddress;
    setIsSaving(true);
    setActionError(null);

    try {
      const newId = await addAddress({
        firstName: formData?.firstName ?? "",
        lastName: formData?.lastName ?? "",
        phone: formData?.phone ?? "",
        addressLine1: rec.addressLine1,
        additionalInformation: rec.additionalInformation,
        city: rec.city,
        postalCode: rec.postalCode,
        country: rec.country,
        isValidated: true,
      });
      setSelectedId(newId);
      onProceed(newId);
    } catch {
      setActionError("Failed to save address. Please try again.");
    } finally {
      setIsSaving(false);
    }
  }, [validationResult, formData, addAddress, onProceed]);

  const handleKeepOriginal = useCallback(async () => {
    const isValid =
      validationResult?.validationValue === "valid" ||
      validationResult?.validationValue === "partially_valid";

    if (revalidatingAddressId) {
      setIsSaving(true);
      setActionError(null);
      try {
        await markValidated(revalidatingAddressId, isValid);
        onProceed(revalidatingAddressId);
      } catch {
        setActionError("Failed to update address. Please try again.");
      } finally {
        setIsSaving(false);
      }
      return;
    }

    if (!formData) return;
    setIsSaving(true);
    setActionError(null);

    try {
      const newId = await addAddress({
        ...formData,
        isValidated: isValid,
      });
      setSelectedId(newId);
      onProceed(newId);
    } catch {
      setActionError("Failed to save address. Please try again.");
    } finally {
      setIsSaving(false);
    }
  }, [formData, validationResult, addAddress, onProceed, revalidatingAddressId, markValidated]);

  const handleEditAddress = useCallback(() => {
    setMode("form");
    setValidationResult(null);
    setRevalidatingAddressId(null);
    resetValidation();
  }, [resetValidation]);

  const handleAddNew = useCallback(() => {
    setFormData(null);
    setValidationResult(null);
    setRevalidatingAddressId(null);
    setShippoFailed(false);
    setActionError(null);
    resetValidation();
    setMode("form");
  }, [resetValidation]);

  const handleCancelForm = useCallback(() => {
    if (addresses.length > 0) {
      setFormData(null);
      setValidationResult(null);
      setRevalidatingAddressId(null);
      setShippoFailed(false);
      setActionError(null);
      resetValidation();
      setMode("select");
    }
  }, [addresses.length, resetValidation]);

  const isProcessing = isValidating || isSaving;

  return (
    <div className="flex flex-col gap-6">
      {actionError && (
        <Alert status={shippoFailed ? "warning" : "danger"} role="alert">
          <Alert.Indicator />
          <Alert.Content>
            <Alert.Title>
              {shippoFailed ? "Address verification unavailable" : "Something went wrong"}
            </Alert.Title>
            <Alert.Description>{actionError}</Alert.Description>
          </Alert.Content>
        </Alert>
      )}

      <div className="grid grid-cols-1 gap-6 lg:grid-cols-[1fr,340px] lg:items-start">
        {/* Main content area */}
        <div className="relative">
          {isProcessing && (
            <div className="absolute inset-0 z-10 flex items-center justify-center rounded-lg bg-background/60">
              <div className="flex flex-col items-center gap-2">
                <Spinner size="lg" />
                <p className="text-sm text-default-500">
                  {isValidating ? "Validating address\u2026" : "Saving address\u2026"}
                </p>
              </div>
            </div>
          )}

          {mode === "select" && (
            <AddressSelector
              addresses={addresses}
              selectedId={selectedId}
              onSelect={handleSelectAddress}
              onAddNew={handleAddNew}
              isLoading={isLoadingAddresses}
            />
          )}

          {mode === "form" && (
            <>
              <AddressForm
                initialData={formData ?? undefined}
                onSubmit={handleFormSubmit}
                onCancel={addresses.length > 0 ? handleCancelForm : undefined}
                isSubmitting={isProcessing}
                validationError={shippoFailed ? null : validationError}
              />
              {shippoFailed && formData && (
                <div className="mt-4 rounded-lg border border-warning-200 bg-warning-50 p-4">
                  <p className="text-sm text-warning-700">
                    We couldn&apos;t verify your address right now. You can save it and
                    continue &mdash; we&apos;ll verify it later.
                  </p>
                  <Button
                    variant="ghost"
                    className="mt-3 w-full md:w-auto"
                    onPress={handleSaveWithoutValidation}
                    isDisabled={isSaving}
                  >
                    Save without verification
                  </Button>
                </div>
              )}
            </>
          )}

          {mode === "feedback" && validationResult && (
            <AddressValidationFeedback
              result={validationResult}
              onAcceptRecommended={handleAcceptRecommended}
              onKeepOriginal={handleKeepOriginal}
              onEditAddress={handleEditAddress}
            />
          )}
        </div>

        {/* Sticky sidebar with navigation */}
        <div className="lg:sticky lg:top-8 lg:self-start">
          <Card className="rounded-lg p-4">
            <Card.Content className="flex flex-col gap-3 p-0">
              <p className="text-sm font-semibold text-foreground">Shipping address</p>
              {selectedId && mode === "select" && (
                <SelectedAddressPreview
                  address={addresses.find((a) => a.id === selectedId)}
                />
              )}

              <div className="flex flex-col gap-2">
                {mode === "select" && (
                  <Button
                    variant="primary"
                    className="w-full bg-[#236f6b] font-medium text-white"
                    size="lg"
                    onPress={shippoFailed ? handleSaveWithoutValidation : handleContinue}
                    isDisabled={!selectedId || isProcessing}
                  >
                    {shippoFailed ? "Continue without verification" : "Continue to review"}
                  </Button>
                )}
                <Button
                  variant="ghost"
                  className="w-full md:w-auto"
                  onPress={onBack}
                  isDisabled={isProcessing}
                >
                  Back to review
                </Button>
              </div>
            </Card.Content>
          </Card>
        </div>
      </div>
    </div>
  );
}

function SelectedAddressPreview({ address }: { address: CheckoutAddress | undefined }) {
  if (!address) return null;

  return (
    <div className="rounded-md border border-default-200 p-3 text-sm text-default-600">
      <p className="font-medium text-foreground">{address.fullName}</p>
      <p>{address.addressLine1}</p>
      {address.additionalInformation && <p>{address.additionalInformation}</p>}
      <p>{address.city}</p>
      <p>{address.postalCode}</p>
    </div>
  );
}
