'use client';

import type {
  CommandGlobalRules,
  CommandOverrideDashboard,
  DiscordChannelOption
} from '@nexumi/shared';
import { RotateCcw } from 'lucide-react';
import { useSearchParams } from 'next/navigation';
import { useEffect, useMemo, useState } from 'react';
import { toast } from 'sonner';
import { useTranslations } from '@/components/locale-provider';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { DiscordResourceMultiSelect } from '@/components/ui/discord-resource-multi-select';
import { DiscordRoleMultiSelect } from '@/components/ui/discord-role-select';
import { Input } from '@/components/ui/input';
import { Switch } from '@/components/ui/switch';

interface LocalOverride extends CommandOverrideDashboard {
  saving?: boolean;
}

interface CommandsManagerProps {
  guildId: string;
  initialCommands: CommandOverrideDashboard[];
  initialGlobalRules: CommandGlobalRules;
  channels: DiscordChannelOption[];
}

export function CommandsManager({
  guildId,
  initialCommands,
  initialGlobalRules,
  channels
}: CommandsManagerProps) {
  const t = useTranslations();
  const searchParams = useSearchParams();
  const [commands, setCommands] = useState<LocalOverride[]>(initialCommands);
  const [search, setSearch] = useState('');
  const [globalRules, setGlobalRules] = useState(initialGlobalRules);
  const [globalSaving, setGlobalSaving] = useState(false);
  const [globalDirty, setGlobalDirty] = useState(false);

  const channelOptions = useMemo(
    () => channels.map((channel) => ({ id: channel.id, name: channel.name, prefix: '#' })),
    [channels]
  );

  useEffect(() => {
    const q = searchParams.get('q');
    if (q) {
      setSearch(q);
    }
  }, [searchParams]);

  const filtered = useMemo(() => {
    const query = search.trim().toLowerCase();
    if (!query) {
      return commands;
    }
    return commands.filter((entry) => entry.commandName.toLowerCase().includes(query));
  }, [commands, search]);

  function patchLocal(commandName: string, patch: Partial<LocalOverride>) {
    setCommands((prev) =>
      prev.map((entry) => (entry.commandName === commandName ? { ...entry, ...patch } : entry))
    );
  }

  function patchGlobal(patch: Partial<CommandGlobalRules>) {
    setGlobalRules((prev) => ({ ...prev, ...patch }));
    setGlobalDirty(true);
  }

  async function handleSaveGlobal() {
    setGlobalSaving(true);
    try {
      const response = await fetch(`/api/guilds/${guildId}/commands/globals`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(globalRules)
      });
      const body = (await response.json().catch(() => null)) as (CommandGlobalRules & { error?: string }) | null;
      if (!response.ok || !body) {
        toast.error(body?.error ?? t('common.saveError'));
        return;
      }
      setGlobalRules({
        allowedChannelIds: body.allowedChannelIds,
        deniedChannelIds: body.deniedChannelIds
      });
      setGlobalDirty(false);
      toast.success(t('common.saveSuccess'));
    } catch {
      toast.error(t('common.saveError'));
    } finally {
      setGlobalSaving(false);
    }
  }

  async function handleSave(entry: LocalOverride) {
    patchLocal(entry.commandName, { saving: true });
    try {
      const response = await fetch(`/api/guilds/${guildId}/commands/${entry.commandName}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          enabled: entry.enabled,
          allowedRoleIds: entry.allowedRoleIds,
          deniedRoleIds: entry.deniedRoleIds,
          allowedChannelIds: entry.allowedChannelIds,
          deniedChannelIds: entry.deniedChannelIds,
          cooldownSeconds: entry.cooldownSeconds
        })
      });
      const body = (await response.json().catch(() => null)) as
        | (CommandOverrideDashboard & { error?: string })
        | null;
      if (!response.ok || !body) {
        toast.error(body?.error ?? t('common.saveError'));
        return;
      }
      patchLocal(entry.commandName, body);
      toast.success(t('common.saveSuccess'));
    } catch {
      toast.error(t('common.saveError'));
    } finally {
      patchLocal(entry.commandName, { saving: false });
    }
  }

  async function handleReset(entry: LocalOverride) {
    patchLocal(entry.commandName, { saving: true });
    try {
      const response = await fetch(`/api/guilds/${guildId}/commands/${entry.commandName}`, {
        method: 'DELETE'
      });
      const body = (await response.json().catch(() => null)) as CommandOverrideDashboard | null;
      if (!response.ok || !body) {
        toast.error(t('common.saveError'));
        return;
      }
      patchLocal(entry.commandName, body);
      toast.success(t('common.saveSuccess'));
    } catch {
      toast.error(t('common.saveError'));
    } finally {
      patchLocal(entry.commandName, { saving: false });
    }
  }

  return (
    <div className="space-y-6">
      <Card>
        <CardHeader>
          <CardTitle>{t('modulePages.commands.globalTitle')}</CardTitle>
          <CardDescription>{t('modulePages.commands.globalDescription')}</CardDescription>
        </CardHeader>
        <CardContent className="space-y-4">
          <div className="space-y-2">
            <div id="field-commands-global-allow" className="scroll-mt-24 space-y-2">
              <p className="text-sm font-medium">{t('modulePages.commands.globalAllowedChannels')}</p>
              <p className="text-xs text-muted-foreground">{t('modulePages.commands.globalAllowedHint')}</p>
              <DiscordResourceMultiSelect
                options={channelOptions}
                value={globalRules.allowedChannelIds}
                onChange={(allowedChannelIds) => patchGlobal({ allowedChannelIds })}
                placeholder={t('modulePages.commands.channelSearchPlaceholder')}
                disabled={globalSaving}
              />
            </div>
          </div>
          <div className="space-y-2">
            <div id="field-commands-global-deny" className="scroll-mt-24 space-y-2">
              <p className="text-sm font-medium">{t('modulePages.commands.globalDeniedChannels')}</p>
              <p className="text-xs text-muted-foreground">{t('modulePages.commands.globalDeniedHint')}</p>
              <DiscordResourceMultiSelect
                options={channelOptions}
                value={globalRules.deniedChannelIds}
                onChange={(deniedChannelIds) => patchGlobal({ deniedChannelIds })}
                placeholder={t('modulePages.commands.channelSearchPlaceholder')}
                disabled={globalSaving}
              />
            </div>
          </div>
          <div className="flex justify-end">
            <Button
              type="button"
              disabled={!globalDirty || globalSaving}
              onClick={() => void handleSaveGlobal()}
            >
              {globalSaving ? t('common.saving') : t('common.save')}
            </Button>
          </div>
        </CardContent>
      </Card>

      <Card>
        <CardHeader>
          <CardTitle>{t('modulePages.commands.title')}</CardTitle>
          <CardDescription>{t('modulePages.commands.description')}</CardDescription>
        </CardHeader>
        <CardContent className="space-y-4">
          <Input
            value={search}
            onChange={(event) => setSearch(event.target.value)}
            placeholder={t('modulePages.commands.searchPlaceholder')}
            className="max-w-sm"
          />
          <div className="space-y-3">
            {filtered.length === 0 && (
              <p className="text-sm text-muted-foreground">{t('modulePages.commands.empty')}</p>
            )}
            {filtered.map((entry) => (
              <div key={entry.commandName} className="space-y-3 rounded-md border border-border p-4">
                <div className="flex flex-wrap items-center justify-between gap-2">
                  <p className="font-mono text-sm font-medium">/{entry.commandName}</p>
                  <div className="flex items-center gap-2">
                    <Switch
                      checked={entry.enabled}
                      disabled={entry.saving}
                      onCheckedChange={(enabled) => patchLocal(entry.commandName, { enabled })}
                    />
                    <span className="text-xs text-muted-foreground">
                      {entry.enabled ? t('common.enabled') : t('common.disabled')}
                    </span>
                  </div>
                </div>
                <div className="grid gap-3 sm:grid-cols-2">
                  <div className="space-y-1">
                    <p className="text-xs text-muted-foreground">{t('modulePages.commands.cooldownSeconds')}</p>
                    <Input
                      type="number"
                      min={0}
                      value={entry.cooldownSeconds ?? ''}
                      onChange={(event) =>
                        patchLocal(entry.commandName, {
                          cooldownSeconds: event.target.value === '' ? null : Number(event.target.value)
                        })
                      }
                      placeholder={t('common.optional')}
                    />
                  </div>
                  <div className="space-y-1 sm:col-span-2">
                    <p className="text-xs text-muted-foreground">{t('modulePages.commands.allowedRoleIds')}</p>
                    <DiscordRoleMultiSelect
                      guildId={guildId}
                      value={entry.allowedRoleIds}
                      onChange={(allowedRoleIds) => patchLocal(entry.commandName, { allowedRoleIds })}
                      placeholder={t('modulePages.commands.roleSearchPlaceholder')}
                      disabled={entry.saving}
                    />
                  </div>
                  <div className="space-y-1 sm:col-span-2">
                    <p className="text-xs text-muted-foreground">{t('modulePages.commands.deniedRoleIds')}</p>
                    <DiscordRoleMultiSelect
                      guildId={guildId}
                      value={entry.deniedRoleIds}
                      onChange={(deniedRoleIds) => patchLocal(entry.commandName, { deniedRoleIds })}
                      placeholder={t('modulePages.commands.roleSearchPlaceholder')}
                      disabled={entry.saving}
                    />
                  </div>
                  <div className="space-y-1 sm:col-span-2">
                    <p className="text-xs text-muted-foreground">{t('modulePages.commands.allowedChannelIds')}</p>
                    <DiscordResourceMultiSelect
                      options={channelOptions}
                      value={entry.allowedChannelIds}
                      onChange={(allowedChannelIds) =>
                        patchLocal(entry.commandName, { allowedChannelIds })
                      }
                      placeholder={t('modulePages.commands.channelSearchPlaceholder')}
                      disabled={entry.saving}
                    />
                  </div>
                  <div className="space-y-1 sm:col-span-2">
                    <p className="text-xs text-muted-foreground">{t('modulePages.commands.deniedChannelIds')}</p>
                    <DiscordResourceMultiSelect
                      options={channelOptions}
                      value={entry.deniedChannelIds}
                      onChange={(deniedChannelIds) =>
                        patchLocal(entry.commandName, { deniedChannelIds })
                      }
                      placeholder={t('modulePages.commands.channelSearchPlaceholder')}
                      disabled={entry.saving}
                    />
                  </div>
                </div>
                <div className="flex justify-end gap-2">
                  <Button
                    type="button"
                    variant="ghost"
                    size="sm"
                    disabled={entry.saving}
                    onClick={() => void handleReset(entry)}
                  >
                    <RotateCcw className="size-4" />
                    {t('modulePages.commands.reset')}
                  </Button>
                  <Button
                    type="button"
                    variant="outline"
                    size="sm"
                    disabled={entry.saving}
                    onClick={() => void handleSave(entry)}
                  >
                    {entry.saving ? t('common.saving') : t('common.save')}
                  </Button>
                </div>
              </div>
            ))}
          </div>
        </CardContent>
      </Card>
    </div>
  );
}
