"use client";

/**
 * JapanAddressForm - Complete Japanese address form with ZIP code lookup
 *
 * Features:
 * - ZIP code lookup via Japan Post API (required)
 * - Auto-fill prefecture, city, town from ZIP (read-only)
 * - Progressive disclosure with smooth animations
 * - House/Apartment toggle with conditional room number
 * - Captures both Japanese and English (romanized) addresses
 * - Compatible with WHMCS and Salesforce field mapping
 */

import { useCallback, useState, useEffect, useRef } from "react";
import { Home, Building2, CheckCircle2, MapPin, ChevronRight, Sparkles } from "lucide-react";
import { Input } from "@/components/atoms";
import { FormField } from "@/components/molecules/FormField/FormField";
import { cn } from "@/shared/utils";
import { ZipCodeInput } from "./ZipCodeInput";
import {
  type BilingualAddress,
  type JapanPostAddress,
  RESIDENCE_TYPE,
  type ResidenceType,
} from "@customer-portal/domain/address";

// ============================================================================
// Types
// ============================================================================

export type JapanAddressFormData = BilingualAddress;

/**
 * Type for partial initial values that allows undefined residenceType.
 * This is needed because with exactOptionalPropertyTypes, Partial<T>
 * makes properties optional but doesn't allow explicitly setting undefined.
 */
type JapanAddressFormInitialValues = Omit<JapanAddressFormData, "residenceType"> & {
  residenceType?: ResidenceType | undefined;
};

export interface JapanAddressFormProps {
  /** Initial address values */
  initialValues?: Partial<JapanAddressFormInitialValues> | undefined;
  /** Called when any address field changes */
  onChange?: ((address: JapanAddressFormData, isComplete: boolean) => void) | undefined;
  /** Field-level errors (keyed by field name) */
  errors?: Partial<Record<keyof JapanAddressFormData, string | undefined>> | undefined;
  /** Fields that have been touched */
  touched?: Partial<Record<keyof JapanAddressFormData, boolean | undefined>> | undefined;
  /** Mark a field as touched */
  onBlur?: ((field: keyof JapanAddressFormData) => void) | undefined;
  /** Whether the form is disabled */
  disabled?: boolean | undefined;
  /** Custom class name for container */
  className?: string | undefined;
  /** Custom content to render when address is complete (replaces default success message) */
  completionContent?: React.ReactNode | undefined;
}

// ============================================================================
// Default Values
// ============================================================================

const DEFAULT_ADDRESS: Omit<JapanAddressFormData, "residenceType"> & {
  residenceType: ResidenceType | "";
} = {
  postcode: "",
  prefecture: "",
  prefectureJa: "",
  city: "",
  cityJa: "",
  town: "",
  townJa: "",
  streetAddress: "",
  buildingName: "",
  roomNumber: "",
  residenceType: "",
};

// ============================================================================
// Street Address Validation
// ============================================================================

/**
 * Validates Japanese street address format (chome-ban-go system)
 * Valid patterns:
 * - "1-2-3" (chome-banchi-go)
 * - "1-2" (chome-banchi)
 * - "12-34-5" (larger numbers)
 * - "1" (single number for some rural areas)
 *
 * Requirements:
 * - Must start with a number
 * - Can contain numbers separated by hyphens
 * - Minimum 1 digit required
 */
function isValidStreetAddress(value: string): boolean {
  const trimmed = value.trim();
  if (!trimmed) return false;

  // Pattern: starts with digit(s), optionally followed by hyphen-digit groups
  // Examples: "1", "1-2", "1-2-3", "12-34-5"
  const pattern = /^\d+(-\d+)*$/;
  return pattern.test(trimmed);
}

function getStreetAddressError(value: string): string | undefined {
  const trimmed = value.trim();
  if (!trimmed) return "Street address is required";
  if (!isValidStreetAddress(trimmed)) {
    return "Enter a valid format (e.g., 1-2-3)";
  }
  return undefined;
}

// ============================================================================
// Animation Wrapper Component
// ============================================================================

function AnimatedSection({
  show,
  children,
  delay = 0,
}: {
  show: boolean;
  children: React.ReactNode;
  delay?: number;
}) {
  return (
    <div
      className={cn(
        "grid transition-all duration-500 ease-out",
        show ? "grid-rows-[1fr] opacity-100" : "grid-rows-[0fr] opacity-0"
      )}
      style={{ transitionDelay: show ? `${delay}ms` : "0ms" }}
    >
      <div className="overflow-hidden">{children}</div>
    </div>
  );
}

// ============================================================================
// Progress Step Indicator
// ============================================================================

function ProgressIndicator({
  currentStep,
  totalSteps,
}: {
  currentStep: number;
  totalSteps: number;
}) {
  return (
    <div className="flex items-center gap-1.5 mb-6">
      {Array.from({ length: totalSteps }).map((_, i) => (
        <div
          key={i}
          className={cn(
            "h-1 rounded-full transition-all duration-500",
            i < currentStep
              ? "bg-primary flex-[2]"
              : i === currentStep
                ? "bg-primary/40 flex-[2] animate-pulse"
                : "bg-border flex-1"
          )}
        />
      ))}
    </div>
  );
}

// ============================================================================
// Bilingual Field Display
// ============================================================================

function BilingualValue({
  romaji,
  japanese,
  placeholder,
  verified,
}: {
  romaji: string;
  japanese?: string;
  placeholder: string;
  verified: boolean;
}) {
  if (!verified) {
    return <span className="text-muted-foreground/60 italic text-sm">{placeholder}</span>;
  }

  return (
    <div className="flex items-baseline gap-2">
      <span className="text-foreground font-medium">{romaji}</span>
      {japanese && <span className="text-muted-foreground text-sm">({japanese})</span>}
    </div>
  );
}

// ============================================================================
// Main Component
// ============================================================================

type InternalFormState = Omit<JapanAddressFormData, "residenceType"> & {
  residenceType: ResidenceType | "";
};

export function JapanAddressForm({
  initialValues,
  onChange,
  errors = {},
  touched = {},
  onBlur,
  disabled = false,
  className,
  completionContent,
}: JapanAddressFormProps) {
  const [address, setAddress] = useState<InternalFormState>(() => ({
    ...DEFAULT_ADDRESS,
    ...initialValues,
    // Convert undefined residenceType to empty string for internal state
    residenceType: initialValues?.residenceType ?? DEFAULT_ADDRESS.residenceType,
  }));

  const [isAddressVerified, setIsAddressVerified] = useState(false);
  const [verifiedZipCode, setVerifiedZipCode] = useState<string>("");
  const [showSuccess, setShowSuccess] = useState(false);

  const onChangeRef = useRef(onChange);
  onChangeRef.current = onChange;

  const streetAddressRef = useRef<HTMLInputElement>(null);
  const focusTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const hasInitializedRef = useRef(false);

  // Calculate current step for progress
  const getCurrentStep = () => {
    if (!isAddressVerified) return 0;
    if (!address.streetAddress.trim()) return 1;
    if (!address.residenceType) return 2;
    if (address.residenceType === RESIDENCE_TYPE.APARTMENT && !address.roomNumber?.trim()) return 3;
    return 4;
  };

  const currentStep = getCurrentStep();

  // Only apply initialValues on first mount to avoid resetting user edits
  useEffect(() => {
    if (initialValues && !hasInitializedRef.current) {
      hasInitializedRef.current = true;
      setAddress(prev => ({
        ...prev,
        ...initialValues,
        // Convert undefined residenceType to empty string for internal state
        residenceType: initialValues.residenceType ?? prev.residenceType,
      }));
      if (initialValues.prefecture && initialValues.city && initialValues.town) {
        setIsAddressVerified(true);
        setVerifiedZipCode(initialValues.postcode || "");
      }
    }
  }, [initialValues]);

  // Cleanup timeout on unmount
  useEffect(() => {
    return () => {
      if (focusTimeoutRef.current) {
        clearTimeout(focusTimeoutRef.current);
      }
    };
  }, []);

  const getError = (field: keyof JapanAddressFormData): string | undefined => {
    return touched[field] ? errors[field] : undefined;
  };

  // Calculate form completion status
  const hasResidenceType =
    address.residenceType === RESIDENCE_TYPE.HOUSE ||
    address.residenceType === RESIDENCE_TYPE.APARTMENT;

  const baseFieldsFilled =
    address.postcode.trim() !== "" &&
    address.prefecture.trim() !== "" &&
    address.city.trim() !== "" &&
    address.town.trim() !== "" &&
    isValidStreetAddress(address.streetAddress);

  // Get street address validation error for display
  const streetAddressError = getStreetAddressError(address.streetAddress);

  const roomNumberOk =
    address.residenceType !== RESIDENCE_TYPE.APARTMENT || (address.roomNumber?.trim() ?? "") !== "";

  // Building name is required for both houses and apartments
  const buildingNameOk = (address.buildingName?.trim() ?? "") !== "";

  const isComplete =
    isAddressVerified && hasResidenceType && baseFieldsFilled && buildingNameOk && roomNumberOk;

  // Notify parent of changes - only send valid typed address when residenceType is set
  useEffect(() => {
    if (hasResidenceType) {
      // Safe to cast since we verified residenceType is valid
      onChangeRef.current?.(address as JapanAddressFormData, isComplete);
    } else {
      // Send incomplete state with partial data (parent should check isComplete flag)
      onChangeRef.current?.(address as JapanAddressFormData, false);
    }
  }, [address, isAddressVerified, hasResidenceType, isComplete]);

  // Manage success animation separately to avoid callback double-firing
  useEffect(() => {
    setShowSuccess(isComplete);
  }, [isComplete]);

  const handleZipChange = useCallback(
    (value: string) => {
      const normalizedNew = value.replace(/-/g, "");
      const normalizedVerified = verifiedZipCode.replace(/-/g, "");
      const shouldReset = normalizedNew !== normalizedVerified;

      if (shouldReset) {
        setIsAddressVerified(false);
        setShowSuccess(false);
        setAddress(prev => ({
          ...prev,
          postcode: value,
          prefecture: "",
          prefectureJa: "",
          city: "",
          cityJa: "",
          town: "",
          townJa: "",
          buildingName: prev.buildingName,
          roomNumber: prev.roomNumber,
          residenceType: prev.residenceType,
        }));
      } else {
        setAddress(prev => ({ ...prev, postcode: value }));
      }
    },
    [verifiedZipCode]
  );

  const handleAddressFound = useCallback((found: JapanPostAddress) => {
    setAddress(prev => {
      setIsAddressVerified(true);
      setVerifiedZipCode(prev.postcode);
      return {
        ...prev,
        prefecture: found.prefectureRoma,
        city: found.cityRoma,
        town: found.townRoma,
        prefectureJa: found.prefecture,
        cityJa: found.city,
        townJa: found.town,
      };
    });

    // Focus street address input after lookup (with cleanup tracking)
    if (focusTimeoutRef.current) {
      clearTimeout(focusTimeoutRef.current);
    }
    focusTimeoutRef.current = setTimeout(() => {
      streetAddressRef.current?.focus();
      focusTimeoutRef.current = null;
    }, 300);
  }, []);

  const handleLookupComplete = useCallback((found: boolean) => {
    if (!found) {
      setIsAddressVerified(false);
      setAddress(prev => ({
        ...prev,
        prefecture: "",
        prefectureJa: "",
        city: "",
        cityJa: "",
        town: "",
        townJa: "",
      }));
    }
  }, []);

  const handleResidenceTypeChange = useCallback((type: ResidenceType) => {
    setAddress(prev => ({
      ...prev,
      residenceType: type,
      roomNumber: type === RESIDENCE_TYPE.HOUSE ? "" : prev.roomNumber,
    }));
  }, []);

  const handleStreetAddressChange = useCallback((value: string) => {
    setAddress(prev => ({ ...prev, streetAddress: value }));
  }, []);

  const handleBuildingNameChange = useCallback((value: string) => {
    setAddress(prev => ({ ...prev, buildingName: value }));
  }, []);

  const handleRoomNumberChange = useCallback((value: string) => {
    setAddress(prev => ({ ...prev, roomNumber: value }));
  }, []);

  const isApartment = address.residenceType === RESIDENCE_TYPE.APARTMENT;

  return (
    <div className={cn("space-y-6", className)}>
      {/* Progress Indicator */}
      <ProgressIndicator currentStep={currentStep} totalSteps={4} />

      {/* Step 1: ZIP Code Lookup */}
      <div>
        <div className="flex items-center gap-2 mb-3">
          <div
            className={cn(
              "flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold transition-all duration-300",
              isAddressVerified
                ? "bg-success text-success-foreground"
                : "bg-primary/10 text-primary"
            )}
          >
            {isAddressVerified ? <CheckCircle2 className="w-4 h-4" /> : "1"}
          </div>
          <span className="text-sm font-medium text-foreground">Enter ZIP Code</span>
          {isAddressVerified && (
            <span className="text-xs text-success font-medium ml-auto flex items-center gap-1">
              <Sparkles className="w-3 h-3" />
              Verified
            </span>
          )}
        </div>

        <ZipCodeInput
          value={address.postcode}
          onChange={handleZipChange}
          onAddressFound={handleAddressFound}
          onLookupComplete={handleLookupComplete}
          error={getError("postcode")}
          required
          disabled={disabled}
          autoFocus
        />
      </div>

      {/* Verified Address Display */}
      <AnimatedSection show={isAddressVerified}>
        <div
          className={cn(
            "rounded-xl border transition-all duration-500",
            "bg-gradient-to-br from-success/5 via-success/[0.02] to-transparent",
            "border-success/20"
          )}
        >
          <div className="p-4 space-y-3">
            <div className="flex items-center gap-2 text-success">
              <MapPin className="w-4 h-4" />
              <span className="text-sm font-semibold">Address from Japan Post</span>
            </div>

            <div className="grid gap-2">
              {/* Prefecture */}
              <div className="flex items-center gap-3 py-2 px-3 rounded-lg bg-background/50">
                <span className="text-xs text-muted-foreground w-20 shrink-0">Prefecture</span>
                <ChevronRight className="w-3 h-3 text-muted-foreground/50" />
                <BilingualValue
                  romaji={address.prefecture}
                  japanese={address.prefectureJa}
                  placeholder="—"
                  verified={isAddressVerified}
                />
              </div>

              {/* City */}
              <div className="flex items-center gap-3 py-2 px-3 rounded-lg bg-background/50">
                <span className="text-xs text-muted-foreground w-20 shrink-0">City / Ward</span>
                <ChevronRight className="w-3 h-3 text-muted-foreground/50" />
                <BilingualValue
                  romaji={address.city}
                  japanese={address.cityJa}
                  placeholder="—"
                  verified={isAddressVerified}
                />
              </div>

              {/* Town */}
              <div className="flex items-center gap-3 py-2 px-3 rounded-lg bg-background/50">
                <span className="text-xs text-muted-foreground w-20 shrink-0">Town</span>
                <ChevronRight className="w-3 h-3 text-muted-foreground/50" />
                <BilingualValue
                  romaji={address.town}
                  japanese={address.townJa}
                  placeholder="—"
                  verified={isAddressVerified}
                />
              </div>
            </div>
          </div>
        </div>
      </AnimatedSection>

      {/* Step 2: Street Address */}
      <AnimatedSection show={isAddressVerified} delay={100}>
        <div>
          <div className="flex items-center gap-2 mb-3">
            <div
              className={cn(
                "flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold transition-all duration-300",
                isValidStreetAddress(address.streetAddress)
                  ? "bg-success text-success-foreground"
                  : "bg-primary/10 text-primary"
              )}
            >
              {isValidStreetAddress(address.streetAddress) ? (
                <CheckCircle2 className="w-4 h-4" />
              ) : (
                "2"
              )}
            </div>
            <span className="text-sm font-medium text-foreground">Street Address</span>
          </div>

          <FormField
            label=""
            error={
              getError("streetAddress") || (address.streetAddress.trim() && streetAddressError)
            }
            required
            helperText={
              address.streetAddress.trim()
                ? streetAddressError
                  ? undefined
                  : "Valid format"
                : "Enter chome-banchi-go (e.g., 1-5-3)"
            }
          >
            <Input
              ref={streetAddressRef}
              value={address.streetAddress}
              onChange={e => handleStreetAddressChange(e.target.value)}
              onBlur={() => onBlur?.("streetAddress")}
              placeholder="1-5-3"
              disabled={disabled}
              className="font-mono text-lg tracking-wider"
              data-field="address.streetAddress"
            />
          </FormField>
        </div>
      </AnimatedSection>

      {/* Step 3: Residence Type */}
      <AnimatedSection
        show={isAddressVerified && isValidStreetAddress(address.streetAddress)}
        delay={150}
      >
        <div>
          <div className="flex items-center gap-2 mb-3">
            <div
              className={cn(
                "flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold transition-all duration-300",
                hasResidenceType
                  ? "bg-success text-success-foreground"
                  : "bg-primary/10 text-primary"
              )}
            >
              {hasResidenceType ? <CheckCircle2 className="w-4 h-4" /> : "3"}
            </div>
            <span className="text-sm font-medium text-foreground">Residence Type</span>
          </div>

          <div className="grid grid-cols-2 gap-3">
            <button
              type="button"
              onClick={() => handleResidenceTypeChange(RESIDENCE_TYPE.HOUSE)}
              disabled={disabled}
              className={cn(
                "group relative flex flex-col items-center gap-2 p-4 rounded-xl border-2 transition-all duration-300",
                "hover:scale-[1.02] active:scale-[0.98]",
                address.residenceType === RESIDENCE_TYPE.HOUSE
                  ? "border-primary bg-primary/5 shadow-[0_0_0_4px] shadow-primary/10"
                  : "border-border bg-card hover:border-primary/50 hover:bg-primary/[0.02]",
                disabled && "opacity-50 cursor-not-allowed hover:scale-100"
              )}
            >
              <div
                className={cn(
                  "w-12 h-12 rounded-xl flex items-center justify-center transition-all duration-300",
                  address.residenceType === RESIDENCE_TYPE.HOUSE
                    ? "bg-primary text-primary-foreground"
                    : "bg-muted text-muted-foreground group-hover:bg-primary/10 group-hover:text-primary"
                )}
              >
                <Home className="w-6 h-6" />
              </div>
              <span
                className={cn(
                  "text-sm font-semibold transition-colors",
                  address.residenceType === RESIDENCE_TYPE.HOUSE
                    ? "text-primary"
                    : "text-foreground"
                )}
              >
                House
              </span>
            </button>

            <button
              type="button"
              onClick={() => handleResidenceTypeChange(RESIDENCE_TYPE.APARTMENT)}
              disabled={disabled}
              className={cn(
                "group relative flex flex-col items-center gap-2 p-4 rounded-xl border-2 transition-all duration-300",
                "hover:scale-[1.02] active:scale-[0.98]",
                address.residenceType === RESIDENCE_TYPE.APARTMENT
                  ? "border-primary bg-primary/5 shadow-[0_0_0_4px] shadow-primary/10"
                  : "border-border bg-card hover:border-primary/50 hover:bg-primary/[0.02]",
                disabled && "opacity-50 cursor-not-allowed hover:scale-100"
              )}
            >
              <div
                className={cn(
                  "w-12 h-12 rounded-xl flex items-center justify-center transition-all duration-300",
                  address.residenceType === RESIDENCE_TYPE.APARTMENT
                    ? "bg-primary text-primary-foreground"
                    : "bg-muted text-muted-foreground group-hover:bg-primary/10 group-hover:text-primary"
                )}
              >
                <Building2 className="w-6 h-6" />
              </div>
              <span
                className={cn(
                  "text-sm font-semibold transition-colors",
                  address.residenceType === RESIDENCE_TYPE.APARTMENT
                    ? "text-primary"
                    : "text-foreground"
                )}
              >
                Apartment
              </span>
            </button>
          </div>

          {!hasResidenceType && getError("residenceType") && (
            <p className="text-sm text-danger mt-2">{getError("residenceType")}</p>
          )}
        </div>
      </AnimatedSection>

      {/* Step 4: Building Details */}
      <AnimatedSection show={isAddressVerified && hasResidenceType} delay={200}>
        <div className="space-y-4">
          <div className="flex items-center gap-2 mb-3">
            <div
              className={cn(
                "flex items-center justify-center w-6 h-6 rounded-full text-xs font-semibold transition-all duration-300",
                showSuccess ? "bg-success text-success-foreground" : "bg-primary/10 text-primary"
              )}
            >
              {showSuccess ? <CheckCircle2 className="w-4 h-4" /> : "4"}
            </div>
            <span className="text-sm font-medium text-foreground">Building Details</span>
          </div>

          {/* Building Name */}
          <FormField
            label="Building Name"
            error={getError("buildingName")}
            required
            helperText={
              isApartment
                ? "e.g., Sunshine Mansion (サンシャインマンション)"
                : "e.g., Tanaka Residence (田中邸)"
            }
          >
            <Input
              value={address.buildingName ?? ""}
              onChange={e => handleBuildingNameChange(e.target.value)}
              onBlur={() => onBlur?.("buildingName")}
              placeholder={isApartment ? "Sunshine Mansion" : "Tanaka Residence"}
              disabled={disabled}
              data-field="address.buildingName"
            />
          </FormField>

          {/* Room Number - Only for apartments */}
          {isApartment && (
            <FormField
              label="Room Number"
              error={getError("roomNumber")}
              required
              helperText="Required for apartments (部屋番号)"
            >
              <Input
                value={address.roomNumber ?? ""}
                onChange={e => handleRoomNumberChange(e.target.value)}
                onBlur={() => onBlur?.("roomNumber")}
                placeholder="201"
                disabled={disabled}
                className="font-mono"
                data-field="address.roomNumber"
              />
            </FormField>
          )}
        </div>
      </AnimatedSection>

      {/* Success State - shows custom content or default message */}
      <AnimatedSection show={showSuccess} delay={250}>
        {completionContent ?? (
          <div className="rounded-xl bg-gradient-to-br from-success/10 via-success/5 to-transparent border border-success/20 p-4">
            <div className="flex items-center gap-3">
              <div className="w-10 h-10 rounded-full bg-success/20 flex items-center justify-center">
                <CheckCircle2 className="w-5 h-5 text-success" />
              </div>
              <div>
                <p className="text-sm font-semibold text-foreground">Address Complete</p>
                <p className="text-xs text-muted-foreground">All address fields have been filled</p>
              </div>
            </div>
          </div>
        )}
      </AnimatedSection>
    </div>
  );
}
