'use client';

import { useEffect, useMemo, useState } from 'react';
import { Chrome, Loader2, Save, ToggleLeft, ToggleRight } from 'lucide-react';
import { useAuth } from '@/components/id/auth-provider';
import { AdminShell } from '@/components/id/admin-shell';
import { usePublicSettings } from '@/components/id/public-settings-provider';
import { useToast } from '@/components/id/toast-provider';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { MessagingSettingsSection } from '@/components/id/messaging-settings-section';
import { SettingsFieldRow } from '@/components/id/settings-field-row';
import { apiFetch, buildSystemSettingPayload, SocialProvider, SystemSetting } from '@/lib/api';
import {
  getSettingMeta,
  isSettingVisible,
  MESSAGING_SETTING_KEYS,
  sortSettingsByCatalog,
  SYSTEM_SETTING_GROUPS
} from '@/lib/system-settings-catalog';

const GROUP_LABELS: Record<string, string> = {
  ...SYSTEM_SETTING_GROUPS,
  'messaging-email': 'Email (SMTP)',
  'messaging-sms': 'SMS'
};

const PUBLIC_SETTINGS_REFRESH_KEYS = new Set(['PROJECT_NAME', 'PROJECT_TAGLINE', 'LDAP_ENABLED', 'LDAP_USE_LDAPS']);

export default function AdminSettingsPage() {
  const { token, user } = useAuth();
  const { showToast } = useToast();
  const { refreshPublicSettings } = usePublicSettings();
  const [settings, setSettings] = useState<SystemSetting[]>([]);
  const [providers, setProviders] = useState<SocialProvider[]>([]);
  const [loading, setLoading] = useState(true);
  const [savingGroup, setSavingGroup] = useState<string | null>(null);
  const [savingOAuthProvider, setSavingOAuthProvider] = useState<string | null>(null);

  useEffect(() => {
    if (!token || !user?.canManageSettings) return;
    Promise.all([
      apiFetch<{ settings: SystemSetting[] }>('/admin/settings', {}, token),
      apiFetch<{ providers: SocialProvider[] }>('/admin/settings/oauth/providers', {}, token)
    ])
      .then(([settingsResponse, providersResponse]) => {
        setSettings(sortSettingsByCatalog(settingsResponse.settings ?? []));
        setProviders(providersResponse.providers ?? []);
      })
      .catch((error) => showToast(error instanceof Error ? error.message : 'Не удалось загрузить настройки'))
      .finally(() => setLoading(false));
  }, [showToast, token, user?.canManageSettings]);

  const groupedSettings = useMemo(() => {
    const groups = new Map<string, SystemSetting[]>();
    for (const setting of settings) {
      if (MESSAGING_SETTING_KEYS.includes(setting.key)) continue;
      const meta = getSettingMeta(setting.key);
      const group = meta?.group ?? 'other';
      const list = groups.get(group) ?? [];
      list.push(setting);
      groups.set(group, list);
    }
    return groups;
  }, [settings]);

  async function saveSettingsGroup(groupKey: string, groupSettings: SystemSetting[]) {
    if (!token) return;

    const visibleSettings = groupSettings.filter((setting) => isSettingVisible(setting, settings));
    if (visibleSettings.length === 0) return;

    setSavingGroup(groupKey);
    try {
      let needsPublicRefresh = false;
      for (const setting of visibleSettings) {
        const updated = await apiFetch<SystemSetting>(
          '/admin/settings',
          {
            method: 'PUT',
            body: JSON.stringify(buildSystemSettingPayload(setting))
          },
          token
        );
        setSettings((current) => sortSettingsByCatalog(current.map((item) => (item.key === updated.key ? updated : item))));
        if (PUBLIC_SETTINGS_REFRESH_KEYS.has(updated.key)) {
          needsPublicRefresh = true;
        }
      }
      if (needsPublicRefresh) {
        await refreshPublicSettings();
      }
      showToast(`Блок «${GROUP_LABELS[groupKey] ?? groupKey}» сохранён`);
    } catch (error) {
      showToast(error instanceof Error ? error.message : 'Не удалось сохранить настройки блока');
    } finally {
      setSavingGroup(null);
    }
  }

  function updateSettingValue(key: string, value: string) {
    setSettings((current) => current.map((item) => (item.key === key ? { ...item, value } : item)));
  }

  function toProviderPayload(provider: SocialProvider) {
    return {
      providerName: provider.providerName,
      clientId: provider.clientId,
      isEnabled: provider.isEnabled
    };
  }

  async function toggleProvider(provider: SocialProvider) {
    if (!token) return;
    try {
      const updated = await apiFetch<SocialProvider>(
        '/admin/settings/oauth/providers',
        {
          method: 'PUT',
          body: JSON.stringify({ ...toProviderPayload(provider), isEnabled: !provider.isEnabled })
        },
        token
      );
      setProviders((current) => current.map((item) => (item.providerName === updated.providerName ? updated : item)));
      showToast(updated.isEnabled ? 'Провайдер включён' : 'Провайдер отключён');
    } catch (error) {
      showToast(error instanceof Error ? error.message : 'Не удалось обновить провайдера');
    }
  }

  async function saveOAuthProvider(provider: SocialProvider) {
    if (!token) return;
    setSavingOAuthProvider(provider.providerName);
    try {
      await apiFetch('/admin/settings/oauth/providers', {
        method: 'PUT',
        body: JSON.stringify(toProviderPayload(provider))
      }, token);
      showToast(`Провайдер ${provider.providerName} сохранён`);
    } catch (error) {
      showToast(error instanceof Error ? error.message : 'Ошибка сохранения провайдера');
    } finally {
      setSavingOAuthProvider(null);
    }
  }

  if (!user?.canManageSettings) {
    return (
      <AdminShell active="/admin/settings">
        <p className="text-[#667085]">У вас нет прав на изменение глобальных настроек.</p>
      </AdminShell>
    );
  }

  return (
    <AdminShell active="/admin/settings">
      <div className="mb-6">
        <h2 className="text-2xl font-medium">Глобальные настройки</h2>
        <p className="mt-2 text-[#667085]">
          Параметры сгруппированы по блокам — измените нужные поля и сохраните весь блок одной кнопкой.
        </p>
      </div>

      {loading ? (
        <div className="flex items-center justify-center gap-2 py-16 text-[#667085]">
          <Loader2 className="h-5 w-5 animate-spin" />
          Загрузка...
        </div>
      ) : (
        <>
          {[...groupedSettings.entries()].map(([groupKey, groupSettings]) => {
            const visibleSettings = groupSettings.filter((setting) => isSettingVisible(setting, settings));
            const saving = savingGroup === groupKey;

            return (
              <section key={groupKey} className="mb-10">
                <div className="rounded-[24px] bg-[#f4f5f8] p-5">
                  <div className="mb-4 flex flex-col gap-3 border-b border-[#e0e3ea] pb-4 md:flex-row md:items-center md:justify-between">
                    <h3 className="text-xl font-medium">{SYSTEM_SETTING_GROUPS[groupKey] ?? 'Прочие настройки'}</h3>
                    <Button
                      disabled={saving || visibleSettings.length === 0}
                      onClick={() => void saveSettingsGroup(groupKey, groupSettings)}
                    >
                      {saving ? <Loader2 className="h-4 w-4 animate-spin" /> : <Save className="h-4 w-4" />}
                      Сохранить блок
                    </Button>
                  </div>

                  <div>
                    {visibleSettings.map((setting) => (
                      <SettingsFieldRow
                        key={setting.key}
                        setting={setting}
                        onChange={(value) => updateSettingValue(setting.key, value)}
                      />
                    ))}
                  </div>
                </div>
              </section>
            );
          })}

          <MessagingSettingsSection
            settings={settings}
            token={token}
            savingGroup={savingGroup}
            onUpdateValue={updateSettingValue}
            onSaveGroup={saveSettingsGroup}
            showToast={showToast}
          />

          <section className="mt-10">
            <h3 className="mb-4 text-xl font-medium">OAuth Social Providers</h3>
            <div className="grid gap-4 md:grid-cols-2">
              {(providers.length
                ? providers
                : [
                    { id: 'google', providerName: 'google', clientId: '', isEnabled: false },
                    { id: 'yandex', providerName: 'yandex', clientId: '', isEnabled: false }
                  ]
              ).map((provider) => (
                <div key={provider.providerName} className="rounded-[24px] bg-[#f4f5f8] p-5">
                  <div className="flex items-center justify-between">
                    {provider.providerName === 'google' ? (
                      <Chrome className="h-7 w-7" />
                    ) : (
                      <div className="flex h-8 w-8 items-center justify-center rounded-full bg-red-500 font-bold text-white">
                        Я
                      </div>
                    )}
                    <button type="button" aria-label="Переключить провайдера" onClick={() => void toggleProvider(provider)}>
                      {provider.isEnabled ? (
                        <ToggleRight className="h-8 w-8 text-green-600" />
                      ) : (
                        <ToggleLeft className="h-8 w-8 text-[#a8adbc]" />
                      )}
                    </button>
                  </div>
                  <h4 className="mt-5 font-semibold capitalize">{provider.providerName}</h4>
                  <p className="mt-1 text-sm text-[#667085]">
                    {provider.isEnabled ? 'Провайдер включен глобально.' : 'Провайдер отключен.'}
                  </p>
                  <Input
                    className="mt-4 bg-white"
                    value={provider.clientId}
                    placeholder="Client ID"
                    onChange={(event) =>
                      setProviders((current) =>
                        current.map((item) =>
                          item.providerName === provider.providerName ? { ...item, clientId: event.target.value } : item
                        )
                      )
                    }
                  />
                  <Button
                    className="mt-3"
                    disabled={savingOAuthProvider === provider.providerName}
                    onClick={() => void saveOAuthProvider(provider)}
                  >
                    {savingOAuthProvider === provider.providerName ? (
                      <Loader2 className="h-4 w-4 animate-spin" />
                    ) : (
                      <Save className="h-4 w-4" />
                    )}
                    Сохранить блок
                  </Button>
                </div>
              ))}
            </div>
          </section>
        </>
      )}
    </AdminShell>
  );
}
