import { FormEvent, useEffect, useMemo } from 'react';

import { useForm, usePage } from '@inertiajs/react';

import { ErrorMessage } from '@/Components/ui/error-message';
import { Input } from '@/Components/ui/input';
import { Label } from '@/Components/ui/label';
import { LoadingButton } from '@/Components/ui/loading-button';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/Components/ui/select';
import type { PageProps } from '@/types';

// IANA timezone list with try/catch fallback for older browsers
const FALLBACK_TIMEZONES = [
  'UTC',
  'America/New_York',
  'America/Chicago',
  'America/Denver',
  'America/Los_Angeles',
  'America/Toronto',
  'America/Vancouver',
  'America/Sao_Paulo',
  'Europe/London',
  'Europe/Paris',
  'Europe/Berlin',
  'Europe/Amsterdam',
  'Europe/Moscow',
  'Asia/Tokyo',
  'Asia/Shanghai',
  'Asia/Singapore',
  'Asia/Dubai',
  'Asia/Mumbai',
  'Australia/Sydney',
  'Pacific/Auckland',
];

function getSupportedTimezones(): string[] {
  try {
    const zones = Intl.supportedValuesOf('timeZone') as string[];
    // 'UTC' is a valid IANA timezone but is excluded from supportedValuesOf in some
    // V8/browser versions. Ensure it is always present so the default value binds.
    return zones.includes('UTC') ? zones : ['UTC', ...zones];
  } catch {
    return FALLBACK_TIMEZONES;
  }
}

/**
 * Normalise an IANA timezone identifier so it matches an entry in the
 * supported list. Some persisted values may be legacy aliases (e.g. 'US/Eastern',
 * 'Europe/Kiev') that the browser silently remaps but does not list. Resolving
 * them through Intl gives us the canonical identifier that IS in the list.
 * Falls back to 'UTC' if the value cannot be resolved.
 */
function normalizeTimezone(tz: string, supportedList: string[]): string {
  if (supportedList.includes(tz)) return tz;
  try {
    const canonical = Intl.DateTimeFormat(undefined, { timeZone: tz }).resolvedOptions().timeZone;
    if (supportedList.includes(canonical)) return canonical;
  } catch {
    // invalid timezone string — fall through to 'UTC'
  }
  return 'UTC';
}

/**
 * Detect the browser's local IANA timezone. Falls back to 'UTC' for SSR
 * or environments where Intl is not fully available.
 */
function getBrowserTimezone(): string {
  try {
    return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
  } catch {
    return 'UTC';
  }
}

interface UpdateProfileInformationFormProps {
  _mustVerifyEmail?: boolean;
  status?: string;
  className?: string;
  timezone?: string;
}

export default function UpdateProfileInformationForm({
  status,
  className = '',
  timezone: initialTimezone,
}: UpdateProfileInformationFormProps) {
  const { auth } = usePage<PageProps>().props;
  const timezones = useMemo(() => getSupportedTimezones(), []);

  // Default timezone: use the server-persisted value when available, normalised
  // to a canonical IANA identifier that exists in the options list.
  // For first setup (no saved timezone) we want to detect the browser's
  // local timezone — but Intl.DateTimeFormat() differs between SSR (UTC)
  // and client (user's local tz), causing hydration mismatches. Instead,
  // initialize with the server value (or 'UTC' as a stable SSR-safe
  // fallback) and update to the browser-detected tz client-only in
  // useEffect. The Select picker shows 'UTC' for one React paint cycle,
  // then the user's actual timezone fills in — imperceptible in practice.
  const resolvedInitialTimezone = useMemo(
    () => (initialTimezone ? normalizeTimezone(initialTimezone, timezones) : 'UTC'),
    // timezones is stable (useMemo with []), so this runs only when initialTimezone changes.
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [initialTimezone],
  );

  const { data, setData, patch, processing, errors } = useForm({
    name: auth.user?.name ?? '',
    email: auth.user?.email ?? '',
    timezone: resolvedInitialTimezone,
  });

  useEffect(() => {
    // Only apply browser-detected default when the server sent no timezone
    // (new account, timezone not yet saved). Runs client-only.
    if (!initialTimezone) {
      const detected = getBrowserTimezone();
      const canonical = normalizeTimezone(detected, timezones);
      if (canonical !== 'UTC') {
        setData('timezone', canonical);
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []); // intentionally empty — run once at mount (client only)

  const submit = (e: FormEvent) => {
    e.preventDefault();
    patch(route('profile.update'));
  };

  return (
    <form onSubmit={submit} className={className}>
      <div className="space-y-4">
        <div className="space-y-2">
          <Label htmlFor="name">Name</Label>
          <Input
            id="name"
            type="text"
            value={data.name}
            onChange={(e) => setData('name', e.target.value)}
            placeholder="Your display name"
            disabled={processing}
          />
          <ErrorMessage error={errors.name} variant="inline" />
        </div>

        <div className="space-y-2">
          <Label htmlFor="email">Email</Label>
          <Input
            id="email"
            type="email"
            value={data.email}
            onChange={(e) => setData('email', e.target.value)}
            disabled={processing}
          />
          <ErrorMessage error={errors.email} variant="inline" />
        </div>

        <div className="space-y-2">
          <Label htmlFor="timezone">Timezone</Label>
          <Select
            value={data.timezone}
            onValueChange={(value) => setData('timezone', value)}
            disabled={processing}
          >
            <SelectTrigger id="timezone" className="w-full">
              <SelectValue placeholder="Select timezone" />
            </SelectTrigger>
            <SelectContent>
              {timezones.map((tz) => (
                <SelectItem key={tz} value={tz}>
                  {tz}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
          <ErrorMessage error={errors.timezone} variant="inline" />
        </div>

        {status && (
          <div className="rounded-md bg-success/10 p-3 text-sm text-success-strong">{status}</div>
        )}

        <LoadingButton type="submit" loading={processing}>
          Save Changes
        </LoadingButton>
      </div>
    </form>
  );
}
