import React, { useEffect, useReducer, useCallback } from 'react';
import {
  lookupLocation,
  reverseGeocode,
  validatePincode,
  pincodeHasDeliveryOffice,
  type AddressComponents,
} from '../core/api';
import { checkServiceability, type ServiceabilityResult } from '../core/checkout-api';
import { processLocalityLookup } from '../core/locality';
import type {
  AddressFormProps,
  AddressLabel,
  AdministrativeInfo,
  CompleteAddress,
  LocationAlternative,
} from '../core/types';
import { AddressLabelIcon } from './AddressLabelIcons';

// ─── State ────────────────────────────────────────────────────────────────────

interface ManualFields {
  flatNumber: string;
  floorNumber: string;
  buildingName: string;
  streetName: string;
}

type FormState =
  | { status: 'loading' }
  | { status: 'error'; message: string }
  | {
      status: 'ready';
      adminInfo: AdministrativeInfo;
      alternatives: LocationAlternative[];
      localityOptions: string[];
      selectedLocality: string; // Selected locality name (from adminInfo or alternatives)
      selectedLabel: AddressLabel;
      labelText: string;
      fields: ManualFields;
      submitting: boolean;
      /** At least one India Post office with "Delivery" (not only "Non Delivery") */
      pincodeHasDelivery: boolean;
      serviceabilityResult: ServiceabilityResult | null;
    };

type FormAction =
  | { type: 'LOAD_START' }
  | {
      type: 'LOAD_SUCCESS';
      adminInfo: AdministrativeInfo;
      alternatives: LocationAlternative[];
      addressComponents: AddressComponents;
      pincodeHasDelivery: boolean;
      serviceabilityResult: ServiceabilityResult | null;
      initialValues?: import('../core/types').AddressFormInitialValues;
    }
  | { type: 'LOAD_ERROR'; message: string }
  | { type: 'SET_FIELD'; key: keyof ManualFields; value: string }
  | { type: 'SET_LOCALITY'; locality: string }
  | { type: 'SET_LABEL'; label: AddressLabel }
  | { type: 'SET_LABEL_TEXT'; value: string }
  | { type: 'SUBMIT_START' }
  | { type: 'SUBMIT_END' };

const INITIAL_FIELDS: ManualFields = {
  flatNumber: '',
  floorNumber: '',
  buildingName: '',
  streetName: '',
};

/**
 * Parse addressComponents from Nominatim/OpenStreetMap.
 * - name → Building/Society/POI name
 * - road + suburb → Street/Area
 */
function parseAddressComponents(components: AddressComponents): Partial<ManualFields> {
  const fields: Partial<ManualFields> = {};

  // Building/Society/POI name: prefer 'name' field (most relevant)
  if (components.name) {
    fields.buildingName = components.name;
  } else if (components.building_name) {
    fields.buildingName = components.building_name;
  } else if (components.addr_housename) {
    fields.buildingName = components.addr_housename;
  }

  // Street/Area: combine road + suburb (if available)
  const streetParts: string[] = [];
  if (components.road) {
    streetParts.push(components.road);
  }
  if (components.suburb) {
    streetParts.push(components.suburb);
  }
  if (streetParts.length > 0) {
    fields.streetName = streetParts.join(', ');
  }

  return fields;
}

function reducer(state: FormState, action: FormAction): FormState {
  switch (action.type) {
    case 'LOAD_START':
      return { status: 'loading' };
    case 'LOAD_SUCCESS': {
      // Pre-fill fields from addressComponents, then override with initialValues
      const preFilled = parseAddressComponents(action.addressComponents);
      const iv = action.initialValues;
      const fields: ManualFields = {
        ...INITIAL_FIELDS,
        ...preFilled,
        ...(iv?.flatNumber !== undefined ? { flatNumber: iv.flatNumber } : {}),
        ...(iv?.floorNumber !== undefined ? { floorNumber: iv.floorNumber } : {}),
        ...(iv?.buildingName !== undefined ? { buildingName: iv.buildingName } : {}),
        ...(iv?.streetName !== undefined ? { streetName: iv.streetName } : {}),
      };
      const processed = processLocalityLookup(action.adminInfo, action.alternatives || []);
      let localityOptions = processed.localityOptions;
      let selectedLocality = processed.selectedLocality;
      if (iv?.locality?.trim()) {
        const savedLocality = iv.locality.trim();
        if (!localityOptions.includes(savedLocality)) {
          localityOptions = [savedLocality, ...localityOptions];
        }
        selectedLocality = savedLocality;
      }
      const selectedLabel = iv?.label ?? 'home';
      return {
        status: 'ready',
        adminInfo: processed.adminInfo,
        alternatives: processed.alternatives,
        localityOptions,
        selectedLocality,
        selectedLabel,
        labelText: selectedLabel === 'other' ? (iv?.labelText ?? '') : '',
        fields,
        submitting: false,
        pincodeHasDelivery: action.pincodeHasDelivery,
        serviceabilityResult: action.serviceabilityResult,
      };
    }
    case 'LOAD_ERROR':
      return { status: 'error', message: action.message };
    case 'SET_FIELD':
      if (state.status !== 'ready') return state;
      return { ...state, fields: { ...state.fields, [action.key]: action.value } };
    case 'SET_LOCALITY':
      if (state.status !== 'ready') return state;
      return { ...state, selectedLocality: action.locality };
    case 'SET_LABEL':
      if (state.status !== 'ready') return state;
      return {
        ...state,
        selectedLabel: action.label,
        labelText: action.label === 'other' ? state.labelText : '',
      };
    case 'SET_LABEL_TEXT':
      if (state.status !== 'ready') return state;
      return { ...state, labelText: action.value.slice(0, 64) };
    case 'SUBMIT_START':
      if (state.status !== 'ready') return state;
      return { ...state, submitting: true };
    case 'SUBMIT_END':
      if (state.status !== 'ready') return state;
      return { ...state, submitting: false };
    default:
      return state;
  }
}

// ─── Component ────────────────────────────────────────────────────────────────

const AddressForm: React.FC<AddressFormProps> = ({
  digipin,
  lat,
  lng,
  apiKey,
  apiBaseUrl,
  onAddressComplete,
  onBack,
  onError,
  checkoutConfig,
  serviceabilitySessionToken,
  enableServiceabilityCheck = false,
  showIndiaPostDeliveryWarning = false,
  serviceabilityBlockCheckout,
  onServiceabilityResult,
  initialValues,
  submitLabel = 'Save Address',
}) => {
  const [state, dispatch] = useReducer(reducer, { status: 'loading' });

  // ── Fetch administrative data + address components on mount ────────────────
  const fetchAdminInfo = useCallback(async () => {
    dispatch({ type: 'LOAD_START' });
    try {
      // Call both APIs in parallel:
      // 1. /v1/location/lookup → administrative_info (state, district, pincode) + alternatives
      // 2. /v1/digipin/reverse → addressComponents (name, road, suburb from Nominatim)
      const [adminRes, reverseRes] = await Promise.all([
        lookupLocation(lat, lng, apiKey, apiBaseUrl),
        reverseGeocode(digipin, apiKey, apiBaseUrl),
      ]);

      const pincode = adminRes.data.administrative_info.pincode?.replace(/\D/g, '').slice(0, 6) ?? '';
      if (pincode.length !== 6) {
        dispatch({
          type: 'LOAD_ERROR',
          message:
            'Could not determine a valid 6-digit pincode for this location. Please adjust the map pin.',
        });
        onError?.(new Error('Missing or invalid pincode'));
        return;
      }

      const pinValidation = await validatePincode(pincode, apiKey, apiBaseUrl);

      if (!pinValidation.isValid) {
        dispatch({
          type: 'LOAD_ERROR',
          message:
            'This location resolves to a pincode that is not in the India Post database. Please move the map pin to a valid address.',
        });
        onError?.(new Error('Invalid pincode for location'));
        return;
      }

      const hasDelivery = pincodeHasDeliveryOffice(pinValidation.offices);
      let serviceabilityResult: ServiceabilityResult | null = null;

      if (
        enableServiceabilityCheck
        && checkoutConfig?.functionBaseUrl
        && checkoutConfig.merchantId
        && serviceabilitySessionToken
      ) {
        try {
          serviceabilityResult = await checkServiceability(
            checkoutConfig,
            serviceabilitySessionToken,
            pincode,
            { lat, lng }
          );
          onServiceabilityResult?.(serviceabilityResult);
        } catch {
          // Fail open: merchant serviceability should never block address entry
          // when the checkout-addresses function itself is unreachable.
        }
      }

      dispatch({
        type: 'LOAD_SUCCESS',
        adminInfo: adminRes.data.administrative_info,
        alternatives: adminRes.data.alternatives || [],
        addressComponents: reverseRes.data.addressComponents,
        pincodeHasDelivery: hasDelivery,
        serviceabilityResult,
        initialValues,
      });
    } catch (err) {
      const msg = err instanceof Error ? err.message : 'Failed to fetch address data.';
      dispatch({ type: 'LOAD_ERROR', message: msg });
      onError?.(err instanceof Error ? err : new Error(msg));
    }
  }, [
    digipin,
    lat,
    lng,
    apiKey,
    apiBaseUrl,
    onError,
    checkoutConfig,
    serviceabilitySessionToken,
    enableServiceabilityCheck,
    onServiceabilityResult,
    initialValues,
  ]);

  useEffect(() => {
    void fetchAdminInfo();
  }, [fetchAdminInfo]);

  // ── Submit ────────────────────────────────────────────────────────────────
  const handleSubmit = useCallback(
    (e: React.FormEvent<HTMLFormElement>) => {
      e.preventDefault();
      if (state.status !== 'ready') return;

      const { adminInfo, selectedLocality, selectedLabel, labelText, fields } = state;

      if (selectedLabel === 'other' && !labelText.trim()) return;
      const serviceabilityBlocked =
        state.serviceabilityResult?.checked
        && state.serviceabilityResult.serviceable === false
        && (serviceabilityBlockCheckout ?? state.serviceabilityResult.block_checkout);
      if (serviceabilityBlocked) return;

      const parts: string[] = [
        fields.flatNumber,
        fields.floorNumber ? `Floor ${fields.floorNumber}` : '',
        fields.buildingName,
        fields.streetName,
        selectedLocality, // Use selected locality (may be from alternatives)
        adminInfo.district,
        adminInfo.state,
        adminInfo.pincode,
      ].filter(Boolean);

      const complete: CompleteAddress = {
        digipin,
        lat,
        lng,
        state: adminInfo.state,
        district: adminInfo.district,
        division: adminInfo.division,
        locality: selectedLocality, // Use selected locality
        pincode: adminInfo.pincode,
        delivery: adminInfo.delivery,
        country: adminInfo.country ?? 'India',
        ...fields,
        formattedAddress: parts.join(', '),
        label: selectedLabel,
        ...(selectedLabel === 'other' ? { labelText: labelText.trim() } : {}),
      };

      dispatch({ type: 'SUBMIT_START' });
      try {
        onAddressComplete(complete);
      } finally {
        dispatch({ type: 'SUBMIT_END' });
      }
    },
    [state, digipin, lat, lng, onAddressComplete, serviceabilityBlockCheckout]
  );

  const serviceabilityBlocked =
    state.status === 'ready'
    && state.serviceabilityResult?.checked
    && state.serviceabilityResult.serviceable === false
    && (serviceabilityBlockCheckout ?? state.serviceabilityResult.block_checkout);

  const showMerchantServiceability =
    state.status === 'ready'
    && state.serviceabilityResult?.checked
    && state.serviceabilityResult.serviceable === false;

  const showIndiaPostInfo =
    state.status === 'ready'
    && !state.pincodeHasDelivery
    && state.serviceabilityResult?.serviceable !== true
    && !showMerchantServiceability
    && (state.serviceabilityResult?.show_india_post_delivery_warning ?? showIndiaPostDeliveryWarning);

  return (
    <div className="qr-form-wrapper">
      {/* ── Step header ── */}
      <div className="qr-step-header">
        <button
          type="button"
          className="qr-back-btn"
          onClick={onBack}
          aria-label="Back to map"
        >
          <svg
            aria-hidden="true"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            strokeWidth="2.5"
            strokeLinecap="round"
            strokeLinejoin="round"
          >
            <path d="M19 12H5M12 19l-7-7 7-7" />
          </svg>
        </button>
        <div className="qr-step-badge">2</div>
        <div className="qr-step-text">
          <span className="qr-step-title">Add Address Details</span>
          <span className="qr-step-sub">Flat number and building info</span>
        </div>
      </div>

      {/* ── DigiPin reference strip ── */}
      <div className="qr-form-digipin-strip">
        <svg
          aria-hidden="true"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          strokeWidth="2"
          strokeLinecap="round"
          strokeLinejoin="round"
        >
          <path d="M21 10c0 7-9 13-9 13S3 17 3 10a9 9 0 0118 0z" />
          <circle cx="12" cy="10" r="3" />
        </svg>
        <span className="qr-form-digipin-strip__label">DigiPin</span>
        <span className="qr-form-digipin-strip__code">{digipin}</span>
      </div>

      {/* ── Loading skeleton ── */}
      {state.status === 'loading' && (
        <div className="qr-loading-state" aria-busy="true" aria-label="Fetching address details">
          <div className="qr-spinner qr-spinner--lg" aria-hidden="true" />
          <p className="qr-loading-state__text">Fetching address details…</p>
        </div>
      )}

      {/* ── Error state ── */}
      {state.status === 'error' && (
        <div className="qr-error-state" role="alert">
          <div className="qr-error-state__icon" aria-hidden="true">⚠</div>
          <p className="qr-error-state__msg">{state.message}</p>
          <button
            type="button"
            className="qr-btn qr-btn--secondary qr-btn--sm"
            onClick={() => void fetchAdminInfo()}
          >
            Retry
          </button>
        </div>
      )}

      {/* ── Main form ── */}
      {state.status === 'ready' && (
        <form onSubmit={handleSubmit} className="qr-form" noValidate>
          {/* Auto-filled section */}
          <fieldset className="qr-fieldset">
            <legend className="qr-fieldset__legend">
              <span className="qr-fieldset__icon" aria-hidden="true">📍</span>
              Auto-detected from your digipin
            </legend>

            <div className="qr-auto-grid">
              {/* State */}
              <div className="qr-auto-row">
                <span className="qr-auto-row__label">State</span>
                <span className="qr-auto-row__value">{state.adminInfo.state}</span>
              </div>

              {/* District */}
              <div className="qr-auto-row">
                <span className="qr-auto-row__label">District</span>
                <span className="qr-auto-row__value">{state.adminInfo.district}</span>
              </div>

              {/* Locality - show dropdown if multiple unique localities exist */}
              <div className="qr-auto-row qr-auto-row--full">
                <span className="qr-auto-row__label">Locality</span>
                {state.localityOptions.length > 1 ? (
                  <select
                    className="qr-auto-row__select"
                    value={state.selectedLocality}
                    onChange={(e) => dispatch({ type: 'SET_LOCALITY', locality: e.target.value })}
                    aria-label="Select locality"
                  >
                    {state.localityOptions.map((name) => (
                      <option key={name} value={name}>
                        {name}
                      </option>
                    ))}
                  </select>
                ) : (
                  <span className="qr-auto-row__value">{state.selectedLocality}</span>
                )}
              </div>

              {/* Pincode */}
              <div className="qr-auto-row">
                <span className="qr-auto-row__label">Pincode</span>
                <span className="qr-auto-row__value qr-auto-row__value--pin">
                  {state.adminInfo.pincode}
                </span>
              </div>
            </div>
          </fieldset>

          {showMerchantServiceability && state.serviceabilityResult && (
            <div
              className={`qr-pincode-banner ${
                serviceabilityBlocked
                  ? 'qr-pincode-banner--error'
                  : 'qr-pincode-banner--warning'
              }`}
              role={serviceabilityBlocked ? 'alert' : 'status'}
              aria-live="polite"
            >
              <span className="qr-pincode-banner__icon" aria-hidden="true">
                {serviceabilityBlocked ? '!' : '⚠'}
              </span>
              <div className="qr-pincode-banner__text">
                <strong>
                  {serviceabilityBlocked ? 'Delivery unavailable' : 'Delivery may be limited'}
                </strong>
                <span>
                  {state.serviceabilityResult.message
                    ?? (serviceabilityBlocked
                      ? 'This seller does not currently deliver to this pincode.'
                      : 'This seller recommends confirming delivery availability for this pincode.')}
                </span>
              </div>
            </div>
          )}

          {showIndiaPostInfo && (
            <div
              className="qr-pincode-banner qr-pincode-banner--info"
              role="status"
              aria-live="polite"
            >
              <span className="qr-pincode-banner__icon" aria-hidden="true">i</span>
              <div className="qr-pincode-banner__text">
                <strong>India Post: no home-delivery office</strong>
                <span>
                  Courier partners may still deliver to this pincode.
                </span>
              </div>
            </div>
          )}

          {/* Address label */}
          <fieldset className="qr-fieldset">
            <legend className="qr-fieldset__legend qr-fieldset__legend--compact">Save as</legend>
            <div className="qr-label-picker" role="radiogroup" aria-label="Address label">
              {(
                [
                  { value: 'home' as const, title: 'Home' },
                  { value: 'work' as const, title: 'Work' },
                  { value: 'other' as const, title: 'Other' },
                ] as const
              ).map(({ value, title }) => (
                <button
                  key={value}
                  type="button"
                  role="radio"
                  aria-checked={state.selectedLabel === value}
                  className={`qr-label-picker__option${
                    state.selectedLabel === value ? ' qr-label-picker__option--active' : ''
                  }`}
                  onClick={() => dispatch({ type: 'SET_LABEL', label: value })}
                >
                  <span className="qr-label-picker__icon">
                    <AddressLabelIcon label={value} />
                  </span>
                  <span>{title}</span>
                </button>
              ))}
            </div>
            {state.selectedLabel === 'other' && (
              <div className="qr-label-text-field">
                <label className="qr-field__label" htmlFor="qr-labelText">
                  Label name
                  <span className="qr-required" aria-hidden="true">*</span>
                </label>
                <input
                  id="qr-labelText"
                  type="text"
                  className="qr-field__input"
                  placeholder="e.g. Friend's home, Gym"
                  value={state.labelText}
                  onChange={(e) =>
                    dispatch({ type: 'SET_LABEL_TEXT', value: e.target.value })
                  }
                  maxLength={64}
                  required
                  aria-required="true"
                  autoComplete="off"
                />
              </div>
            )}
          </fieldset>

          {/* Manual entry section */}
          <fieldset className="qr-fieldset">
            <legend className="qr-fieldset__legend">
              <span className="qr-fieldset__icon" aria-hidden="true">🏠</span>
              Your details
            </legend>

            <div className="qr-fields-grid">
              {/* Flat / House – required */}
              <div className="qr-field qr-field--full">
                <label className="qr-field__label" htmlFor="qr-flatNumber">
                  Flat / House Number
                  <span className="qr-required" aria-hidden="true">*</span>
                </label>
                <input
                  id="qr-flatNumber"
                  type="text"
                  className="qr-field__input"
                  placeholder="e.g. 4B, Flat 201, House No. 12"
                  value={state.fields.flatNumber}
                  onChange={(e) =>
                    dispatch({ type: 'SET_FIELD', key: 'flatNumber', value: e.target.value })
                  }
                  autoComplete="address-line1"
                  required
                  aria-required="true"
                />
              </div>

              {/* Floor */}
              <div className="qr-field">
                <label className="qr-field__label" htmlFor="qr-floorNumber">
                  Floor
                  <span className="qr-optional">optional</span>
                </label>
                <input
                  id="qr-floorNumber"
                  type="text"
                  className="qr-field__input"
                  placeholder="e.g. 3rd, Ground"
                  value={state.fields.floorNumber}
                  onChange={(e) =>
                    dispatch({ type: 'SET_FIELD', key: 'floorNumber', value: e.target.value })
                  }
                />
              </div>

              {/* Building / Society */}
              <div className="qr-field">
                <label className="qr-field__label" htmlFor="qr-buildingName">
                  Building / Society
                  <span className="qr-optional">optional</span>
                </label>
                <input
                  id="qr-buildingName"
                  type="text"
                  className="qr-field__input"
                  placeholder="e.g. Sunshine Apts, DDA Colony"
                  value={state.fields.buildingName}
                  onChange={(e) =>
                    dispatch({ type: 'SET_FIELD', key: 'buildingName', value: e.target.value })
                  }
                  autoComplete="address-line2"
                />
              </div>

              {/* Street / Area */}
              <div className="qr-field qr-field--full">
                <label className="qr-field__label" htmlFor="qr-streetName">
                  Street / Area
                  <span className="qr-optional">optional</span>
                </label>
                <input
                  id="qr-streetName"
                  type="text"
                  className="qr-field__input"
                  placeholder="e.g. MG Road, Sector 12"
                  value={state.fields.streetName}
                  onChange={(e) =>
                    dispatch({ type: 'SET_FIELD', key: 'streetName', value: e.target.value })
                  }
                  autoComplete="address-level3"
                />
              </div>
            </div>
          </fieldset>

          {/* Actions */}
          <div className="qr-form-actions">
            <button
              type="button"
              className="qr-btn qr-btn--ghost"
              onClick={onBack}
            >
              <svg
                aria-hidden="true"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
              >
                <path d="M19 12H5M12 19l-7-7 7-7" />
              </svg>
              Adjust Pin
            </button>
            <button
              type="submit"
              className="qr-btn qr-btn--primary qr-btn--grow"
              disabled={
                state.submitting
                || !state.fields.flatNumber.trim()
                || (state.selectedLabel === 'other' && !state.labelText.trim())
                || Boolean(serviceabilityBlocked)
              }
            >
              {state.submitting ? (
                <>
                  <span className="qr-spinner qr-spinner--sm" aria-hidden="true" />
                  Saving…
                </>
              ) : (
                <>
                  {submitLabel}
                  <svg
                    aria-hidden="true"
                    viewBox="0 0 24 24"
                    fill="none"
                    stroke="currentColor"
                    strokeWidth="2.5"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  >
                    <path d="M20 6L9 17l-5-5" />
                  </svg>
                </>
              )}
            </button>
          </div>
        </form>
      )}
    </div>
  );
};

export default AddressForm;
