'use client';

import { useState, useEffect, useMemo, useRef } from 'react';
import { Save, KeyRound, Globe, Upload } from 'lucide-react';

import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Switch } from '@/components/ui/switch';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { PageHeader } from '@/components/shared/page-header';
import { CountryCombobox } from '@/components/shared/country-combobox';
import { TimezoneCombobox } from '@/components/shared/timezone-combobox';
import { ImageCropperDialog } from '@/components/shared/image-cropper-dialog';
import { apiFetch } from '@/lib/api/client';
import { primaryTimezoneFor } from '@/lib/i18n/timezones';
import type { CountryCode } from '@/lib/i18n/countries';

interface NotificationPrefs {
  reminder_due: boolean;
  reminder_overdue: boolean;
  eoi_signed: boolean;
  eoi_completed: boolean;
  invoice_overdue: boolean;
  duplicate_alert: boolean;
  [key: string]: boolean;
}

interface MeResponse {
  user?: { name: string; email: string };
  preferences?: { country?: string; timezone?: string };
  profile?: { avatarFileId?: string | null };
}

export function UserSettings() {
  const [notifPrefs, setNotifPrefs] = useState<NotificationPrefs | null>(null);
  const [displayName, setDisplayName] = useState('');
  const [phone, setPhone] = useState('');
  const [email, setEmail] = useState('');
  const [originalEmail, setOriginalEmail] = useState('');
  const [country, setCountry] = useState<string | null>(null);
  const [timezone, setTimezone] = useState<string | null>(null);
  const [saving, setSaving] = useState<string | null>(null);
  const [message, setMessage] = useState<string | null>(null);
  const [resetMsg, setResetMsg] = useState<string | null>(null);
  const [emailMsg, setEmailMsg] = useState<string | null>(null);
  const [avatarFileId, setAvatarFileId] = useState<string | null>(null);
  const [avatarUrl, setAvatarUrl] = useState<string | null>(null);
  const [pendingAvatarFile, setPendingAvatarFile] = useState<File | null>(null);
  const [cropperOpen, setCropperOpen] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);

  // Browser-detected timezone — surfaces a banner when the rep is
  // travelling and the saved value no longer matches their device's
  // locale. Quietly absent in SSR; the picker still works without it.
  const detectedTz = useMemo(() => {
    if (typeof Intl === 'undefined') return null;
    try {
      return Intl.DateTimeFormat().resolvedOptions().timeZone;
    } catch {
      return null;
    }
  }, []);

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

  async function loadProfile() {
    const res = await apiFetch<{ data: MeResponse }>('/api/v1/me', { method: 'GET' });
    setDisplayName(res.data.user?.name ?? '');
    setEmail(res.data.user?.email ?? '');
    setOriginalEmail(res.data.user?.email ?? '');
    setCountry(res.data.preferences?.country ?? null);
    setTimezone(res.data.preferences?.timezone ?? null);
    const fid = res.data.profile?.avatarFileId ?? null;
    setAvatarFileId(fid);
    setAvatarUrl(fid ? `/api/v1/files/${fid}/preview` : null);
  }

  function handleAvatarPicked(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0] ?? null;
    if (!file) return;
    setPendingAvatarFile(file);
    setCropperOpen(true);
    // Reset so picking the same file twice still triggers onChange.
    if (fileInputRef.current) fileInputRef.current.value = '';
  }

  async function uploadAvatar(blob: Blob) {
    const fd = new FormData();
    fd.append('file', new File([blob], 'avatar.jpg', { type: 'image/jpeg' }));
    const res = await fetch('/api/v1/me/avatar', { method: 'POST', body: fd });
    if (!res.ok) throw new Error('Avatar upload failed');
    const json = (await res.json()) as { data: { avatarFileId: string } };
    setAvatarFileId(json.data.avatarFileId);
    // Cache-bust the preview URL with a query so the new image renders.
    setAvatarUrl(`/api/v1/files/${json.data.avatarFileId}/preview?t=${Date.now()}`);
  }

  async function loadNotificationPrefs() {
    try {
      const res = await apiFetch<{ data: NotificationPrefs }>('/api/v1/notifications/preferences');
      setNotifPrefs(res.data);
    } catch {
      setNotifPrefs({
        reminder_due: true,
        reminder_overdue: true,
        eoi_signed: true,
        eoi_completed: true,
        invoice_overdue: true,
        duplicate_alert: true,
      });
    }
  }

  function handleCountryChange(iso: string | null) {
    setCountry(iso);
    // Auto-default timezone when the rep picks a country and hasn't
    // explicitly set a timezone yet. Same trick as the client overview.
    if (iso && !timezone) {
      const tz = primaryTimezoneFor(iso as CountryCode);
      if (tz) setTimezone(tz);
    }
  }

  async function saveProfile() {
    setSaving('profile');
    setMessage(null);
    try {
      await apiFetch('/api/v1/me', {
        method: 'PATCH',
        body: {
          displayName: displayName || undefined,
          phone: phone || null,
          preferences: {
            country: country ?? undefined,
            timezone: timezone ?? undefined,
          },
        },
      });
      setMessage('Profile saved');
    } catch (err: unknown) {
      setMessage(err instanceof Error ? err.message : 'Failed to save');
    } finally {
      setSaving(null);
    }
  }

  async function saveEmail() {
    if (email === originalEmail) return;
    setSaving('email');
    setEmailMsg(null);
    try {
      await apiFetch('/api/v1/me/email', { method: 'PATCH', body: { email } });
      setOriginalEmail(email);
      setEmailMsg('Email updated. Use the new address next time you sign in.');
    } catch (err: unknown) {
      setEmailMsg(err instanceof Error ? err.message : 'Failed to update email');
    } finally {
      setSaving(null);
    }
  }

  async function requestPasswordReset() {
    setSaving('password');
    setResetMsg(null);
    try {
      await apiFetch('/api/v1/me/password-reset', { method: 'POST' });
      setResetMsg('Password-reset email sent. Check your inbox.');
    } catch (err: unknown) {
      setResetMsg(err instanceof Error ? err.message : 'Failed to send reset email');
    } finally {
      setSaving(null);
    }
  }

  async function toggleNotifPref(key: string, value: boolean) {
    setSaving(key);
    try {
      await apiFetch('/api/v1/notifications/preferences', {
        method: 'PATCH',
        body: { [key]: value },
      });
      setNotifPrefs((prev) => (prev ? { ...prev, [key]: value } : prev));
    } finally {
      setSaving(null);
    }
  }

  function adoptDetectedTz() {
    if (detectedTz) setTimezone(detectedTz);
  }

  const NOTIF_LABELS: Record<string, string> = {
    reminder_due: 'Reminder due',
    reminder_overdue: 'Reminder overdue',
    eoi_signed: 'EOI signed by a party',
    eoi_completed: 'EOI fully completed',
    invoice_overdue: 'Invoice overdue',
    duplicate_alert: 'Duplicate client detected',
  };

  const tzMismatch = detectedTz && timezone && detectedTz !== timezone;

  return (
    <div>
      <PageHeader title="Settings" description="Manage your profile and notification preferences" />

      <div className="mt-6 space-y-6 max-w-2xl">
        <Card>
          <CardHeader>
            <CardTitle>Profile</CardTitle>
            <CardDescription>Update your display name and contact info</CardDescription>
          </CardHeader>
          <CardContent className="space-y-4">
            {/* Avatar — click the photo to pick a file, which opens the
                cropper. Cropped result uploads via /api/v1/me/avatar. */}
            <div className="flex items-center gap-4">
              <Avatar className="h-16 w-16">
                {avatarUrl ? <AvatarImage src={avatarUrl} alt="Profile photo" /> : null}
                <AvatarFallback>
                  {(displayName || email || 'U').slice(0, 1).toUpperCase()}
                </AvatarFallback>
              </Avatar>
              <div className="space-y-1">
                <Label className="text-sm">Profile photo</Label>
                <div>
                  <Button
                    type="button"
                    variant="outline"
                    size="sm"
                    onClick={() => fileInputRef.current?.click()}
                  >
                    <Upload className="mr-1.5 h-3.5 w-3.5" />
                    {avatarFileId ? 'Replace photo' : 'Upload photo'}
                  </Button>
                  <input
                    ref={fileInputRef}
                    type="file"
                    accept="image/jpeg,image/png,image/webp"
                    onChange={handleAvatarPicked}
                    className="hidden"
                  />
                </div>
                <p className="text-xs text-muted-foreground">
                  PNG, JPG, or WebP up to 2 MB. You&apos;ll be able to crop after picking.
                </p>
              </div>
            </div>
            <div className="space-y-2">
              <Label htmlFor="settings-name">Display name</Label>
              <Input
                id="settings-name"
                value={displayName}
                onChange={(e) => setDisplayName(e.target.value)}
                placeholder="Your name"
              />
            </div>
            <div className="space-y-2">
              <Label htmlFor="settings-phone">Phone</Label>
              <Input
                id="settings-phone"
                type="tel"
                value={phone}
                onChange={(e) => setPhone(e.target.value)}
                placeholder="+1 555-0123"
              />
            </div>
            <div className="space-y-2">
              <Label>Country</Label>
              <CountryCombobox value={country} onChange={handleCountryChange} />
              <p className="text-xs text-muted-foreground">
                Sets the default timezone when you pick a country and haven&apos;t chosen one
                explicitly.
              </p>
            </div>
            <div className="space-y-2">
              <Label>Timezone</Label>
              <TimezoneCombobox
                value={timezone}
                onChange={setTimezone}
                countryHint={(country as CountryCode | null) ?? undefined}
              />
              {tzMismatch && (
                <div className="flex items-start gap-2 rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-xs text-amber-900">
                  <Globe className="h-3.5 w-3.5 shrink-0 mt-0.5" />
                  <div className="flex-1">
                    Looks like you&apos;re in <strong>{detectedTz}</strong> right now (saved:{' '}
                    {timezone}).
                    <button
                      type="button"
                      onClick={adoptDetectedTz}
                      className="ml-1 underline underline-offset-2 hover:no-underline"
                    >
                      Update?
                    </button>
                  </div>
                </div>
              )}
            </div>
            <div className="flex items-center gap-3">
              <Button onClick={saveProfile} disabled={saving === 'profile'}>
                <Save className="mr-1.5 h-4 w-4" />
                {saving === 'profile' ? 'Saving…' : 'Save profile'}
              </Button>
              {message && <span className="text-sm text-muted-foreground">{message}</span>}
            </div>
          </CardContent>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle>Account</CardTitle>
            <CardDescription>Sign-in email and password</CardDescription>
          </CardHeader>
          <CardContent className="space-y-4">
            <div className="space-y-2">
              <Label htmlFor="settings-email">Email</Label>
              <Input
                id="settings-email"
                type="email"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
              />
              <div className="flex items-center gap-3">
                <Button
                  size="sm"
                  variant="outline"
                  onClick={saveEmail}
                  disabled={saving === 'email' || email === originalEmail || !email}
                >
                  {saving === 'email' ? 'Updating…' : 'Update email'}
                </Button>
                {emailMsg && <span className="text-xs text-muted-foreground">{emailMsg}</span>}
              </div>
              <p className="text-xs text-muted-foreground">
                Changing your email also changes the address you use to sign in.
              </p>
            </div>
            <div className="space-y-2 pt-2 border-t">
              <Label>Password</Label>
              <div className="flex items-center gap-3">
                <Button
                  size="sm"
                  variant="outline"
                  onClick={requestPasswordReset}
                  disabled={saving === 'password'}
                >
                  <KeyRound className="mr-1.5 h-3.5 w-3.5" />
                  {saving === 'password' ? 'Sending…' : 'Send reset email'}
                </Button>
                {resetMsg && <span className="text-xs text-muted-foreground">{resetMsg}</span>}
              </div>
              <p className="text-xs text-muted-foreground">
                We&apos;ll email you a link to set a new password.
              </p>
            </div>
          </CardContent>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle>Notifications</CardTitle>
            <CardDescription>Choose which notifications you receive</CardDescription>
          </CardHeader>
          <CardContent className="space-y-4">
            {notifPrefs &&
              Object.entries(NOTIF_LABELS).map(([key, label]) => (
                <div key={key} className="flex items-center justify-between">
                  <Label>{label}</Label>
                  <Switch
                    checked={notifPrefs[key] ?? true}
                    disabled={saving === key}
                    onCheckedChange={(checked) => toggleNotifPref(key, checked)}
                  />
                </div>
              ))}
          </CardContent>
        </Card>
      </div>

      <ImageCropperDialog
        open={cropperOpen}
        onOpenChange={setCropperOpen}
        file={pendingAvatarFile}
        aspect={1}
        outputWidth={256}
        title="Crop profile photo"
        onUpload={uploadAvatar}
      />
    </div>
  );
}
