'use client';

import React, { useState } from 'react';
import { Input, InputBase, InputGroup, NativeSelect, Textarea, PrivacyCheckbox } from '../elements';
import type { FormDefinition, FormFieldDefinition } from '../../types/api/form';
import countries from '../../utils/countries';

export interface DynamicFormFieldsProps {
  /** Form definition from API (fields array + optional settings). */
  form: FormDefinition;
  /** For job_application forms: add hidden jobSlug input. */
  jobSlug?: string;
}

const INPUT_TYPES = ['text', 'email', 'tel'] as const;

/** Get national-format mask from country (e.g. "(###) ###-####") by stripping country code from phoneMask. */
function getNationalMask(country: (typeof countries)[0] | undefined): string {
  if (!country?.phoneMask) return '';
  const code = country.phoneCode.startsWith('+') ? country.phoneCode : `+${country.phoneCode}`;
  const escaped = code.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  return country.phoneMask.replace(new RegExp(`^\\s*${escaped}[\\s-]*`), '').trim();
}

/** Format digit string into mask; # = one digit. No trailing literals so backspace works. */
function formatDigitsToMask(digits: string, mask: string): string {
  if (digits.length === 0) return '';
  let i = 0;
  let out = '';
  for (const c of mask) {
    if (c === '#') {
      if (i < digits.length) out += digits[i++];
      else break;
    } else if (i < digits.length) {
      out += c;
    }
  }
  return out;
}

function allFieldsFlat(fields: FormDefinition['fields']): FormFieldDefinition[] {
  const out: FormFieldDefinition[] = [];
  for (const item of fields) {
    if (Array.isArray(item)) out.push(...item);
    else if (item && typeof item === 'object' && 'name' in item) out.push(item);
  }
  return out;
}

function renderField(
  field: FormFieldDefinition,
  index: number,
  showCountryCode: boolean,
  selectedCountryPhone: string,
  onCountryChange: (code: string) => void,
  phoneValues: Record<string, string>,
  setPhoneValues: React.Dispatch<React.SetStateAction<Record<string, string>>>
): React.ReactNode {
  const name = field.name ?? `field-${index}`;

  if (field.type === 'hidden') {
    const val = field.value ?? '';
    return <input key={name} type="hidden" name={name} value={val} />;
  }

  if (field.type === 'tel' && showCountryCode) {
    const countryOptions = countries.map((c) => ({
      label: c.phoneCode.startsWith('+') ? c.phoneCode : `+${c.phoneCode}`,
      value: c.code,
    }));
    const country = countries.find((c) => c.code === selectedCountryPhone);
    const nationalMask = getNationalMask(country);
    const value = phoneValues[name] ?? '';
    const placeholder = nationalMask ? nationalMask.replace(/#/g, '0') : (field.placeholder ?? '');

    const handlePhoneChange: (value: string) => void = (value) => {
      const digits = value.replace(/\D/g, '');
      const formatted = nationalMask ? formatDigitsToMask(digits, nationalMask) : digits;
      setPhoneValues((prev) => ({ ...prev, [name]: formatted }));
    };

    return (
      <InputGroup
        key={name}
        label={field.label}
        isRequired={Boolean(field.required)}
        size="md"
        leadingAddon={
          <NativeSelect
            aria-label="Country code"
            value={selectedCountryPhone}
            onChange={(e: React.ChangeEvent<HTMLSelectElement>) =>
              onCountryChange(e.currentTarget.value)
            }
            options={countryOptions}
          />
        }
      >
        <InputBase
          type="tel"
          name={name}
          value={value}
          onChange={handlePhoneChange}
          placeholder={placeholder}
          size="md"
        />
      </InputGroup>
    );
  }

  if (field.type === 'textarea') {
    return (
      <Textarea
        key={name}
        name={name}
        label={field.label}
        placeholder={field.placeholder}
        rows={6}
        isRequired={Boolean(field.required)}
      />
    );
  }

  const inputType = INPUT_TYPES.includes(field.type as (typeof INPUT_TYPES)[number])
    ? (field.type as 'text' | 'email' | 'tel')
    : 'text';
  return (
    <Input
      key={name}
      isRequired={Boolean(field.required)}
      size="md"
      name={name}
      label={field.label}
      type={inputType}
      placeholder={field.placeholder}
    />
  );
}

export function DynamicFormFields({ form, jobSlug }: DynamicFormFieldsProps) {
  const [selectedCountryPhone, setSelectedCountryPhone] = useState('US');
  const [phoneValues, setPhoneValues] = useState<Record<string, string>>({});
  const { settings } = form;
  const fields: FormDefinition['fields'] = Array.isArray(form.fields) ? form.fields : [];

  const handleCountryChange = (newCode: string) => {
    setSelectedCountryPhone(newCode);
    const country = countries.find((c) => c.code === newCode);
    const nationalMask = getNationalMask(country);
    if (!nationalMask) return;
    setPhoneValues((prev) => {
      const next = { ...prev };
      let changed = false;
      for (const name of Object.keys(next)) {
        const digits = next[name].replace(/\D/g, '');
        const formatted = formatDigitsToMask(digits, nationalMask);
        if (formatted !== next[name]) {
          next[name] = formatted;
          changed = true;
        }
      }
      return changed ? next : prev;
    });
  };

  /** Show country code selector for tel fields; default true (US +1) unless backend sets to false. */
  const showCountryCode = settings?.show_country_code !== false;
  const showPrivacyCheckbox = settings?.show_privacy_checkbox !== false;
  const flat = allFieldsFlat(fields);
  const hasPhoneField = flat.some((f) => f.type === 'tel');

  return (
    <div className="flex flex-col gap-6">
      {fields.map((item, index) => {
        if (Array.isArray(item)) {
          if (item.length === 0) return null;
          return (
            <div
              key={`row-${index}`}
              className="flex flex-col gap-x-8 gap-y-6 md:flex-row"
            >
              {item.map((f, i) => (
                <div key={f.name} className="flex-1">
                  {renderField(f, i, showCountryCode, selectedCountryPhone, handleCountryChange, phoneValues, setPhoneValues)}
                </div>
              ))}
            </div>
          );
        }
        return (
          <div key={item.name ?? `field-${index}`}>
            {renderField(item, index, showCountryCode, selectedCountryPhone, handleCountryChange, phoneValues, setPhoneValues)}
          </div>
        );
      })}

      {jobSlug ? <input type="hidden" name="jobSlug" value={jobSlug} /> : null}

      {showPrivacyCheckbox && hasPhoneField && <PrivacyCheckbox />}
    </div>
  );
}
