'use client';

import dynamic from 'next/dynamic';
import { useEffect, useRef, useState } from 'react';
import { Loader2, MapPin, Trash2 } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { useToast } from '@/components/id/toast-provider';
import { ADDRESS_LABELS, type AddressLabel } from '@/lib/address-catalog';
import { forwardGeocode, reverseGeocode } from '@/lib/geocoding';
import { deleteUserAddress, getApiErrorMessage, upsertUserAddress, UserAddress } from '@/lib/api';
import { cn } from '@/lib/utils';

const AddressMapPicker = dynamic(
  () => import('@/components/addresses/address-map-picker').then((module) => module.AddressMapPicker),
  {
    ssr: false,
    loading: () => (
      <div className="flex h-[280px] items-center justify-center rounded-2xl border border-[#eceef4] bg-[#fafbfd] text-sm text-[#667085]">
        <Loader2 className="mr-2 h-4 w-4 animate-spin" />
        Загрузка карты...
      </div>
    )
  }
);

function FieldLabel({ children }: { children: React.ReactNode }) {
  return <label className="block text-sm font-medium text-[#1f2430]">{children}</label>;
}

export function AddressFormDialog({
  open,
  onOpenChange,
  label,
  userId,
  token,
  existing,
  onSaved
}: {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  label: AddressLabel;
  userId: string;
  token?: string | null;
  existing: UserAddress | null;
  onSaved: () => void;
}) {
  const { showToast } = useToast();
  const [mode, setMode] = useState<'map' | 'manual'>('map');
  const [city, setCity] = useState('');
  const [street, setStreet] = useState('');
  const [house, setHouse] = useState('');
  const [apartment, setApartment] = useState('');
  const [comment, setComment] = useState('');
  const [fullAddress, setFullAddress] = useState('');
  const [latitude, setLatitude] = useState<number | undefined>();
  const [longitude, setLongitude] = useState<number | undefined>();
  const [isGeocoding, setIsGeocoding] = useState(false);
  const [isSaving, setIsSaving] = useState(false);
  const [isDeleting, setIsDeleting] = useState(false);
  const geocodeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);

  useEffect(() => {
    if (!open) return;
    setMode(existing?.latitude != null && existing?.longitude != null ? 'map' : existing ? 'manual' : 'map');
    setCity(existing?.city ?? '');
    setStreet(existing?.street ?? '');
    setHouse(existing?.house ?? '');
    setApartment(existing?.apartment ?? '');
    setComment(existing?.comment ?? '');
    setFullAddress(existing?.fullAddress ?? '');
    setLatitude(existing?.latitude);
    setLongitude(existing?.longitude);
  }, [existing, open]);

  useEffect(() => {
    return () => {
      if (geocodeTimer.current) clearTimeout(geocodeTimer.current);
    };
  }, []);

  async function handleMapPick(lat: number, lng: number) {
    setLatitude(lat);
    setLongitude(lng);
    if (geocodeTimer.current) clearTimeout(geocodeTimer.current);
    geocodeTimer.current = setTimeout(async () => {
      setIsGeocoding(true);
      try {
        const parsed = await reverseGeocode(lat, lng);
        if (parsed) {
          setCity(parsed.city);
          setStreet(parsed.street);
          setHouse(parsed.house);
          setFullAddress(parsed.fullAddress);
        }
      } finally {
        setIsGeocoding(false);
      }
    }, 450);
  }

  async function locateManualAddress() {
    const query = fullAddress.trim() || [`г. ${city}`, `${street}, ${house}`].filter(Boolean).join(', ');
    if (!query.trim()) {
      showToast('Сначала укажите адрес для поиска');
      return;
    }
    setIsGeocoding(true);
    try {
      const result = await forwardGeocode(query);
      if (!result) {
        showToast('Адрес не найден на карте');
        return;
      }
      setLatitude(result.lat);
      setLongitude(result.lng);
      setCity(result.parsed.city || city);
      setStreet(result.parsed.street || street);
      setHouse(result.parsed.house || house);
      setFullAddress(result.parsed.fullAddress);
      setMode('map');
    } finally {
      setIsGeocoding(false);
    }
  }

  async function saveAddress() {
    setIsSaving(true);
    try {
      await upsertUserAddress(
        userId,
        {
          addressId: existing?.id,
          label,
          city: city.trim(),
          street: street.trim(),
          house: house.trim(),
          apartment: apartment.trim() || undefined,
          comment: comment.trim() || undefined,
          latitude,
          longitude,
          fullAddress: fullAddress.trim() || undefined
        },
        token
      );
      showToast(existing ? 'Адрес обновлён' : 'Адрес добавлен');
      onSaved();
      onOpenChange(false);
    } catch (error) {
      const message = getApiErrorMessage(error, 'Не удалось сохранить адрес');
      if (message) showToast(message);
    } finally {
      setIsSaving(false);
    }
  }

  async function removeAddress() {
    if (!existing) return;
    setIsDeleting(true);
    try {
      await deleteUserAddress(userId, existing.id, token);
      showToast('Адрес удалён');
      onSaved();
      onOpenChange(false);
    } catch (error) {
      const message = getApiErrorMessage(error, 'Не удалось удалить адрес');
      if (message) showToast(message);
    } finally {
      setIsDeleting(false);
    }
  }

  const title = existing
    ? `Редактировать: ${ADDRESS_LABELS[label].title}`
    : `Добавить: ${ADDRESS_LABELS[label].title}`;

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-h-[92vh] overflow-y-auto rounded-[28px] sm:max-w-[520px]">
        <DialogHeader>
          <DialogTitle>{title}</DialogTitle>
        </DialogHeader>

        <Tabs value={mode} onValueChange={(value) => setMode(value as 'map' | 'manual')}>
          <TabsList className="grid w-full grid-cols-2 bg-[#f4f5f8] p-1">
            <TabsTrigger
              value="map"
              className={cn(
                'rounded-xl px-4 py-2 text-sm data-[state=active]:bg-white data-[state=active]:text-[#1f2430] data-[state=active]:shadow-sm',
                'text-[#667085]'
              )}
            >
              На карте
            </TabsTrigger>
            <TabsTrigger
              value="manual"
              className={cn(
                'rounded-xl px-4 py-2 text-sm data-[state=active]:bg-white data-[state=active]:text-[#1f2430] data-[state=active]:shadow-sm',
                'text-[#667085]'
              )}
            >
              Вручную
            </TabsTrigger>
          </TabsList>

          <TabsContent value="map" className="space-y-4">
            <AddressMapPicker latitude={latitude} longitude={longitude} onPick={handleMapPick} />
            {isGeocoding ? (
              <div className="flex items-center gap-2 text-sm text-[#667085]">
                <Loader2 className="h-4 w-4 animate-spin" />
                Определяем адрес...
              </div>
            ) : fullAddress ? (
              <div className="flex items-start gap-2 rounded-2xl bg-[#f4f5f8] px-4 py-3 text-sm">
                <MapPin className="mt-0.5 h-4 w-4 shrink-0 text-[#667085]" />
                <span>{fullAddress}</span>
              </div>
            ) : (
              <p className="text-sm text-[#667085]">Выберите точку на карте — адрес подставится автоматически</p>
            )}
          </TabsContent>

          <TabsContent value="manual" className="space-y-4">
            <div className="space-y-2">
              <FieldLabel>Полный адрес</FieldLabel>
              <Input
                placeholder="Например: г. Москва, ул. Тверская, 1"
                value={fullAddress}
                onChange={(event) => setFullAddress(event.target.value)}
              />
            </div>
            <Button type="button" variant="secondary" className="w-full" onClick={() => void locateManualAddress()} disabled={isGeocoding}>
              {isGeocoding ? (
                <>
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                  Ищем на карте...
                </>
              ) : (
                'Найти на карте'
              )}
            </Button>
          </TabsContent>
        </Tabs>

        <div className="mt-2 grid gap-3 sm:grid-cols-2">
          <div className="space-y-2 sm:col-span-2">
            <FieldLabel>Город</FieldLabel>
            <Input placeholder="Москва" value={city} onChange={(event) => setCity(event.target.value)} />
          </div>
          <div className="space-y-2">
            <FieldLabel>Улица</FieldLabel>
            <Input placeholder="Тверская" value={street} onChange={(event) => setStreet(event.target.value)} />
          </div>
          <div className="space-y-2">
            <FieldLabel>Дом</FieldLabel>
            <Input placeholder="1" value={house} onChange={(event) => setHouse(event.target.value)} />
          </div>
          <div className="space-y-2">
            <FieldLabel>Квартира</FieldLabel>
            <Input placeholder="Необязательно" value={apartment} onChange={(event) => setApartment(event.target.value)} />
          </div>
          <div className="space-y-2">
            <FieldLabel>Комментарий</FieldLabel>
            <Input placeholder="Подъезд, домофон..." value={comment} onChange={(event) => setComment(event.target.value)} />
          </div>
        </div>

        <div className="mt-6 flex gap-3">
          {existing ? (
            <Button
              type="button"
              variant="secondary"
              className="text-red-600 hover:text-red-700"
              onClick={() => void removeAddress()}
              disabled={isSaving || isDeleting}
            >
              {isDeleting ? <Loader2 className="h-4 w-4 animate-spin" /> : <Trash2 className="h-4 w-4" />}
            </Button>
          ) : null}
          <Button type="button" variant="secondary" className="flex-1" onClick={() => onOpenChange(false)} disabled={isSaving || isDeleting}>
            Отмена
          </Button>
          <Button type="button" className="flex-1" onClick={() => void saveAddress()} disabled={isSaving || isDeleting || isGeocoding}>
            {isSaving ? (
              <>
                <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                Сохраняем...
              </>
            ) : (
              'Сохранить'
            )}
          </Button>
        </div>
      </DialogContent>
    </Dialog>
  );
}
