'use client';

import type { LogChannelMapping, LogEventTypeDashboard, LoggingConfigDashboard } from '@nexumi/shared';
import { Plus, Trash2 } from 'lucide-react';
import { useMemo } from 'react';
import { FieldAnchor } from '@/components/layout/field-anchor';
import { useTranslations } from '@/components/locale-provider';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { DiscordChannelMultiSelect, DiscordChannelSelect } from '@/components/ui/discord-channel-select';
import { DiscordResourceMultiSelect } from '@/components/ui/discord-resource-multi-select';
import { DiscordRoleMultiSelect } from '@/components/ui/discord-role-select';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Switch } from '@/components/ui/switch';
import type { SettingsSaveResult } from '@/components/settings/settings-form';
import { SettingsForm } from '@/components/settings/settings-form';

const LOG_EVENT_TYPES: LogEventTypeDashboard[] = [
  'MESSAGE_EDIT',
  'MESSAGE_DELETE',
  'MESSAGE_BULK_DELETE',
  'MEMBER_JOIN',
  'MEMBER_LEAVE',
  'MEMBER_BAN',
  'MEMBER_UNBAN',
  'MEMBER_UPDATE',
  'CHANNEL_CREATE',
  'CHANNEL_DELETE',
  'CHANNEL_UPDATE',
  'VOICE_JOIN',
  'VOICE_LEAVE',
  'VOICE_MOVE',
  'INVITE_CREATE',
  'EMOJI_CREATE',
  'EMOJI_UPDATE',
  'EMOJI_DELETE',
  'STICKER_CREATE',
  'STICKER_UPDATE',
  'STICKER_DELETE',
  'THREAD_CREATE',
  'THREAD_UPDATE',
  'THREAD_DELETE',
  'GUILD_UPDATE',
  'MOD_ACTION',
  'VERIFICATION_FAIL'
];

interface LocalLogChannelGroup {
  clientKey: string;
  channelId: string;
  eventTypes: LogEventTypeDashboard[];
}

interface LocalLoggingValue {
  enabled: boolean;
  ignoreBots: boolean;
  ignoredChannelIds: string[];
  ignoredRoleIds: string[];
  retentionDays: number;
  logChannels: LocalLogChannelGroup[];
}

function toLocal(config: LoggingConfigDashboard): LocalLoggingValue {
  const byChannel = new Map<string, LogEventTypeDashboard[]>();
  for (const mapping of config.logChannels) {
    const existing = byChannel.get(mapping.channelId) ?? [];
    existing.push(mapping.eventType);
    byChannel.set(mapping.channelId, existing);
  }

  const logChannels: LocalLogChannelGroup[] = [...byChannel.entries()].map(([channelId, eventTypes], index) => ({
    clientKey: `${channelId}-${index}`,
    channelId,
    eventTypes: [...new Set(eventTypes)]
  }));

  return {
    enabled: config.enabled,
    ignoreBots: config.ignoreBots,
    ignoredChannelIds: config.ignoredChannelIds,
    ignoredRoleIds: config.ignoredRoleIds,
    retentionDays: config.retentionDays,
    logChannels
  };
}

function toRemote(value: LocalLoggingValue): { ok: true; value: LoggingConfigDashboard } | { ok: false; error: string } {
  const mappings: LogChannelMapping[] = [];
  const seenEventTypes = new Set<LogEventTypeDashboard>();

  for (const group of value.logChannels) {
    if (!group.channelId.trim() || group.eventTypes.length === 0) {
      continue;
    }
    for (const eventType of group.eventTypes) {
      if (seenEventTypes.has(eventType)) {
        return { ok: false, error: 'duplicateEventType' };
      }
      seenEventTypes.add(eventType);
      mappings.push({ eventType, channelId: group.channelId });
    }
  }

  return {
    ok: true,
    value: {
      enabled: value.enabled,
      ignoreBots: value.ignoreBots,
      ignoredChannelIds: value.ignoredChannelIds,
      ignoredRoleIds: value.ignoredRoleIds,
      retentionDays: value.retentionDays,
      logChannels: mappings
    }
  };
}

async function saveLogging(
  guildId: string,
  value: LocalLoggingValue,
  t: (key: string) => string
): Promise<SettingsSaveResult> {
  const remote = toRemote(value);
  if (!remote.ok) {
    return { ok: false, error: t(`modulePages.logging.errors.${remote.error}`) };
  }

  try {
    const response = await fetch(`/api/guilds/${guildId}/logging`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(remote.value)
    });
    if (!response.ok) {
      const body = (await response.json().catch(() => null)) as { error?: string } | null;
      return { ok: false, error: body?.error ?? `Request failed with status ${response.status}` };
    }
    return { ok: true };
  } catch {
    return { ok: false, error: 'Network error' };
  }
}

interface LoggingFormProps {
  guildId: string;
  initialValue: LoggingConfigDashboard;
}

export function LoggingForm({ guildId, initialValue }: LoggingFormProps) {
  const t = useTranslations();

  const eventOptions = useMemo(
    () =>
      LOG_EVENT_TYPES.map((eventType) => ({
        id: eventType,
        name: t(`modulePages.logging.eventTypes.${eventType}`)
      })),
    [t]
  );

  return (
    <SettingsForm<LocalLoggingValue>
      initialValue={toLocal(initialValue)}
      onSave={(value) => saveLogging(guildId, value, t)}
    >
      {({ value, setValue }) => (
        <div className="space-y-6">
          <Card>
            <CardHeader>
              <CardTitle>{t('modulePages.logging.title')}</CardTitle>
              <CardDescription>{t('modulePages.logging.description')}</CardDescription>
            </CardHeader>
            <CardContent className="space-y-4">
              <FieldAnchor id="field-logging-enabled">
              <div className="flex items-center justify-between rounded-md border border-border p-4">
                <Label>{t('modulePages.logging.enabledLabel')}</Label>
                <Switch
                  checked={value.enabled}
                  onCheckedChange={(checked) => setValue((prev) => ({ ...prev, enabled: checked }))}
                />
              </div>
              </FieldAnchor>
              <FieldAnchor id="field-logging-ignore-bots">
              <div className="flex items-center justify-between rounded-md border border-border p-4">
                <Label>{t('modulePages.logging.ignoreBotsLabel')}</Label>
                <Switch
                  checked={value.ignoreBots}
                  onCheckedChange={(checked) => setValue((prev) => ({ ...prev, ignoreBots: checked }))}
                />
              </div>
              </FieldAnchor>
              <FieldAnchor id="field-logging-ignored-channels">
              <div className="space-y-2">
                <Label>{t('modulePages.logging.ignoredChannelsLabel')}</Label>
                <DiscordChannelMultiSelect
                  guildId={guildId}
                  value={value.ignoredChannelIds}
                  onChange={(ignoredChannelIds) => setValue((prev) => ({ ...prev, ignoredChannelIds }))}
                />
              </div>
              </FieldAnchor>
              <FieldAnchor id="field-logging-ignored-roles">
              <div className="space-y-2">
                <Label>{t('modulePages.logging.ignoredRolesLabel')}</Label>
                <DiscordRoleMultiSelect
                  guildId={guildId}
                  value={value.ignoredRoleIds}
                  onChange={(ignoredRoleIds) => setValue((prev) => ({ ...prev, ignoredRoleIds }))}
                />
              </div>
              </FieldAnchor>
              <FieldAnchor id="field-logging-retention">
              <div className="space-y-2">
                <Label htmlFor="logging-retention">{t('modulePages.logging.retentionLabel')}</Label>
                <Input
                  id="logging-retention"
                  type="number"
                  min={0}
                  max={3650}
                  className="w-40"
                  value={value.retentionDays}
                  onChange={(event) =>
                    setValue((prev) => ({ ...prev, retentionDays: Number(event.target.value) || 0 }))
                  }
                />
                <p className="text-xs text-muted-foreground">{t('modulePages.logging.retentionHint')}</p>
              </div>
              </FieldAnchor>
            </CardContent>
          </Card>

          <FieldAnchor id="field-logging-channels">
          <Card>
            <CardHeader>
              <CardTitle>{t('modulePages.logging.channelsTitle')}</CardTitle>
              <CardDescription>{t('modulePages.logging.channelsDescription')}</CardDescription>
            </CardHeader>
            <CardContent className="space-y-3">
              {value.logChannels.length === 0 && (
                <p className="text-sm text-muted-foreground">{t('modulePages.logging.channelsEmpty')}</p>
              )}
              {value.logChannels.map((mapping) => (
                <div key={mapping.clientKey} className="space-y-3 rounded-md border border-border p-3">
                  <div className="flex flex-wrap items-end gap-3">
                    <div className="min-w-[14rem] flex-1 space-y-2">
                      <Label>{t('modulePages.logging.channelId')}</Label>
                      <DiscordChannelSelect
                        guildId={guildId}
                        value={mapping.channelId}
                        onChange={(channelId) =>
                          setValue((prev) => ({
                            ...prev,
                            logChannels: prev.logChannels.map((entry) =>
                              entry.clientKey === mapping.clientKey ? { ...entry, channelId } : entry
                            )
                          }))
                        }
                      />
                    </div>
                    <Button
                      type="button"
                      variant="ghost"
                      size="icon"
                      aria-label={t('common.remove')}
                      onClick={() =>
                        setValue((prev) => ({
                          ...prev,
                          logChannels: prev.logChannels.filter((entry) => entry.clientKey !== mapping.clientKey)
                        }))
                      }
                    >
                      <Trash2 className="size-4" />
                    </Button>
                  </div>
                  <div className="space-y-2">
                    <Label>{t('modulePages.logging.eventTypesLabel')}</Label>
                    <DiscordResourceMultiSelect
                      options={eventOptions}
                      value={mapping.eventTypes}
                      showIdHint={false}
                      placeholder={t('modulePages.logging.eventTypesPlaceholder')}
                      onChange={(nextIds) => {
                        const eventTypes = nextIds as LogEventTypeDashboard[];
                        setValue((prev) => ({
                          ...prev,
                          logChannels: prev.logChannels.map((entry) => {
                            if (entry.clientKey === mapping.clientKey) {
                              return { ...entry, eventTypes };
                            }
                            // Each event type can only map to one channel (DB unique).
                            return {
                              ...entry,
                              eventTypes: entry.eventTypes.filter((eventType) => !eventTypes.includes(eventType))
                            };
                          })
                        }));
                      }}
                    />
                  </div>
                </div>
              ))}
              <Button
                type="button"
                variant="outline"
                onClick={() =>
                  setValue((prev) => ({
                    ...prev,
                    logChannels: [
                      ...prev.logChannels,
                      { clientKey: `new-${Date.now()}`, channelId: '', eventTypes: [] }
                    ]
                  }))
                }
              >
                <Plus className="size-4" />
                {t('modulePages.logging.addMapping')}
              </Button>
              <p className="text-xs text-muted-foreground">{t('modulePages.logging.channelsHint')}</p>
            </CardContent>
          </Card>
          </FieldAnchor>
        </div>
      )}
    </SettingsForm>
  );
}
