import { useEffect, useState, useMemo, useCallback } from 'react';
import { IconPlus, IconTrash } from '@tabler/icons-react';
import { toc } from '@lobehub/icons';
import { useTranslation } from 'react-i18next';
import { toast } from 'sonner';
import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { AutoComplete } from '@/components/auto-complete';
import { AutoCompleteSelect } from '@/components/auto-complete-select';
import { useModels } from '../context/models-context';
import { DEVELOPER_IDS, DEVELOPER_ICONS } from '../data/constants';
import { useBulkCreateModels } from '../data/models';
import { useDevelopersData } from '../data/providers';
import { type Provider, type ProviderModel } from '../data/providers.schema';
import { CreateModelInput, ModelCard } from '../data/schema';

interface ModelRow {
  id: string;
  modelId: string;
  developer: string;
  name: string;
  icon: string;
  group: string;
  modelCard: ModelCard | null;
}

interface ValidationErrors {
  [rowId: string]: {
    developer?: boolean;
    modelId?: boolean;
    name?: boolean;
    icon?: boolean;
  };
}

const MAX_ROWS = 10;

function generateId(): string {
  return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
}

function isDeveloper(provider: string) {
  return DEVELOPER_IDS.includes(provider);
}

export function ModelsBatchCreateDialog() {
  const { t } = useTranslation();
  const { open, setOpen } = useModels();
  const bulkCreateModels = useBulkCreateModels();
  const { data: developersData } = useDevelopersData();
  const [rows, setRows] = useState<ModelRow[]>([]);
  const [validationErrors, setValidationErrors] = useState<ValidationErrors>({});
  const [dialogContent, setDialogContent] = useState<HTMLDivElement | null>(null);

  const isOpen = open === 'batchCreate';

  const providers = useMemo(() => {
    if (!developersData) return [];
    return Object.entries(developersData.providers)
      .filter(([key]) => isDeveloper(key))
      .map(([key, provider]: [string, Provider]) => ({
        id: key,
        name: provider.display_name || provider.name,
        models: provider.models || [],
      }));
  }, [developersData]);

  const developerOptions = useMemo(() => {
    return DEVELOPER_IDS.map((id) => ({
      value: id,
      label: id,
    }));
  }, []);

  const iconOptions = useMemo(() => {
    return (
      Object.entries(toc)
        // @ts-ignore
        .filter(([_, value]) => value.group == 'provider' || value.group == 'model')
        .map(([_, value]) => ({
          // @ts-ignore
          value: value.id,
          // @ts-ignore
          label: value.id,
        }))
    );
  }, []);

  useEffect(() => {
    if (isOpen && rows.length === 0) {
      setRows([
        {
          id: generateId(),
          modelId: '',
          developer: '',
          name: '',
          icon: '',
          group: '',
          modelCard: null,
        },
      ]);
    }
  }, [isOpen, rows.length]);

  const handleAddRow = useCallback(() => {
    if (rows.length >= MAX_ROWS) {
      toast.error(t('models.dialogs.batchCreate.maxRowsReached', { max: MAX_ROWS }));
      return;
    }
    setRows((prev) => [
      ...prev,
      {
        id: generateId(),
        modelId: '',
        developer: '',
        name: '',
        icon: '',
        group: '',
        modelCard: null,
      },
    ]);
  }, [rows.length, t]);

  const handleRemoveRow = useCallback((id: string) => {
    setRows((prev) => prev.filter((row) => row.id !== id));
  }, []);

  const handleModelIdChange = useCallback(
    (id: string, modelId: string) => {
      setRows((prev) =>
        prev.map((row) => {
          if (row.id !== id) return row;

          if (!row.developer) {
            return { ...row, modelId, name: '', group: '', modelCard: null };
          }

          const provider = providers.find((p) => p.id === row.developer);
          if (!provider) {
            return { ...row, modelId, name: '', group: '', modelCard: null };
          }

          const selectedModel = provider.models.find((m: ProviderModel) => m.id === modelId);
          if (selectedModel) {
            const modelCard: ModelCard = {
              reasoning: {
                supported: selectedModel.reasoning?.supported || false,
                default: selectedModel.reasoning?.default || false,
              },
              toolCall: selectedModel.tool_call || false,
              temperature: selectedModel.temperature || false,
              modalities: {
                input: selectedModel.modalities?.input || [],
                output: selectedModel.modalities?.output || [],
              },
              vision: selectedModel.attachment || false,
              cost: {
                input: selectedModel.cost?.input || 0,
                output: selectedModel.cost?.output || 0,
                cacheRead: selectedModel.cost?.cache_read,
                cacheWrite: selectedModel.cost?.cache_write,
              },
              limit: {
                context: selectedModel.limit?.context || 0,
                output: selectedModel.limit?.output || 0,
              },
              knowledge: selectedModel.knowledge,
              releaseDate: selectedModel.release_date,
              lastUpdated: selectedModel.last_updated,
            };
            return {
              ...row,
              modelId,
              name: selectedModel.display_name || selectedModel.name || '',
              group: selectedModel.family || row.developer,
              modelCard,
            };
          }

          return { ...row, modelId, name: '', group: row.developer, modelCard: null };
        })
      );
    },
    [providers]
  );

  const handleDeveloperChange = useCallback((id: string, developer: string) => {
    setRows((prev) =>
      prev.map((row) => {
        if (row.id !== id) return row;
        const icon = DEVELOPER_ICONS[developer] || developer;
        return {
          ...row,
          developer,
          icon,
          modelId: '',
          name: '',
          group: '',
          modelCard: null,
        };
      })
    );
  }, []);

  const handleNameChange = useCallback((id: string, name: string) => {
    setRows((prev) => prev.map((row) => (row.id === id ? { ...row, name } : row)));
  }, []);

  const handleIconChange = useCallback((id: string, icon: string) => {
    setRows((prev) => prev.map((row) => (row.id === id ? { ...row, icon } : row)));
  }, []);

  const clearValidationError = useCallback(
    (rowId: string, field: keyof ValidationErrors[string]) => {
      if (!validationErrors[rowId]?.[field]) return;

      setValidationErrors((prev) => {
        const newErrors = { ...prev };
        if (newErrors[rowId]) {
          const rowErrors = { ...newErrors[rowId] };
          delete rowErrors[field];
          if (Object.keys(rowErrors).length === 0) {
            delete newErrors[rowId];
          } else {
            newErrors[rowId] = rowErrors;
          }
        }
        return newErrors;
      });
    },
    [validationErrors]
  );

  const handleSubmit = useCallback(async () => {
    const errors: ValidationErrors = {};
    rows.forEach((row) => {
      const rowErrors: ValidationErrors[string] = {};
      if (!row.developer) rowErrors.developer = true;
      if (!row.modelId) rowErrors.modelId = true;
      if (!row.name) rowErrors.name = true;
      if (!row.icon) rowErrors.icon = true;
      if (Object.keys(rowErrors).length > 0) {
        errors[row.id] = rowErrors;
      }
    });

    if (Object.keys(errors).length > 0) {
      setValidationErrors(errors);
      return;
    }

    setValidationErrors({});

    const validRows = rows.filter((row) => row.modelId && row.developer && row.name && row.icon && row.group);

    if (validRows.length === 0) {
      return;
    }

    const inputs: CreateModelInput[] = validRows.map((row) => ({
      developer: row.developer,
      modelID: row.modelId,
      type: 'chat',
      name: row.name,
      icon: row.icon,
      group: row.group,
      modelCard: row.modelCard || {
        reasoning: { supported: false, default: false },
        toolCall: false,
        temperature: false,
        modalities: { input: [], output: [] },
        vision: false,
        cost: { input: 0, output: 0 },
        limit: { context: 0, output: 0 },
      },
      settings: {
        associations: [
          {
            type: 'model',
            priority: 0,
            modelId: {
              modelId: row.modelId,
            },
          },
        ],
      },
    }));

    try {
      await bulkCreateModels.mutateAsync(inputs);
      handleClose();
    } catch (_error) {
      // Error is handled by mutation
    }
  }, [rows, bulkCreateModels, t]);

  const handleClose = useCallback(() => {
    setOpen(null);
    setRows([]);
    setValidationErrors({});
  }, [setOpen]);

  const getModelIdOptions = useCallback(
    (developer: string) => {
      const provider = providers.find((p) => p.id === developer);
      if (!provider) return [];
      return provider.models.map((m: ProviderModel) => ({
        value: m.id,
        label: m.id,
      }));
    },
    [providers]
  );

  return (
    <Dialog open={isOpen} onOpenChange={handleClose}>
      <DialogContent ref={setDialogContent} className='flex flex-col overflow-hidden sm:max-w-4xl' style={{ height: '600px' }}>
        <DialogHeader className='flex-shrink-0 text-left'>
          <DialogTitle>{t('models.dialogs.batchCreate.title')}</DialogTitle>
          <DialogDescription>{t('models.dialogs.batchCreate.description')}</DialogDescription>
        </DialogHeader>

        <div className='min-h-0 flex-1 overflow-x-auto overflow-y-auto pr-2 md:overflow-x-hidden'>
          <div className='min-w-[600px] space-y-2'>
            <div className='flex items-start gap-2 px-2 pb-2'>
              <div className='min-w-32 flex-[2]'>
                <Label className='text-sm font-medium'>{t('models.fields.developer')}</Label>
              </div>
              <div className='min-w-40 flex-[3]'>
                <Label className='text-sm font-medium'>{t('models.fields.modelId')}</Label>
              </div>
              <div className='min-w-24 flex-[2]'>
                <Label className='text-sm font-medium'>{t('models.fields.name')}</Label>
              </div>
              <div className='min-w-32 flex-[3]'>
                <Label className='text-sm font-medium'>{t('models.fields.icon')}</Label>
              </div>
              <div className='w-8 flex-shrink-0'></div>
            </div>
            {rows.map((row) => (
              <div key={row.id} className='rounded-lg border p-2'>
                <div className='flex items-start gap-2'>
                  <div className='min-w-32 flex-[2] space-y-1'>
                    <AutoComplete
                      selectedValue={row.developer}
                      onSelectedValueChange={(value) => {
                        handleDeveloperChange(row.id, value);
                        clearValidationError(row.id, 'developer');
                        clearValidationError(row.id, 'icon');
                      }}
                      searchValue={row.developer}
                      onSearchValueChange={(value) => handleDeveloperChange(row.id, value)}
                      items={developerOptions}
                      placeholder={t('models.fields.developer')}
                      emptyMessage={t('models.fields.noModels')}
                      portalContainer={dialogContent}
                    />
                    {validationErrors[row.id]?.developer && (
                      <p className='text-xs text-red-600'>{t('models.dialogs.batchCreate.required')}</p>
                    )}
                  </div>
                  <div className='min-w-40 flex-[3] space-y-1'>
                    <AutoComplete
                      selectedValue={row.modelId}
                      onSelectedValueChange={(value) => {
                        handleModelIdChange(row.id, value);
                        clearValidationError(row.id, 'modelId');
                        clearValidationError(row.id, 'name');
                        clearValidationError(row.id, 'icon');
                      }}
                      searchValue={row.modelId}
                      onSearchValueChange={(value) => handleModelIdChange(row.id, value)}
                      items={row.developer ? getModelIdOptions(row.developer) : []}
                      placeholder={t('models.fields.modelId')}
                      emptyMessage={t('models.fields.noModels')}
                      portalContainer={dialogContent}
                    />
                    {validationErrors[row.id]?.modelId && (
                      <p className='text-xs text-red-600'>{t('models.dialogs.batchCreate.required')}</p>
                    )}
                  </div>
                  <div className='min-w-24 flex-[2] space-y-1'>
                    <Input
                      value={row.name}
                      onChange={(e) => {
                        handleNameChange(row.id, e.target.value);
                        clearValidationError(row.id, 'name');
                      }}
                      placeholder={t('models.fields.name')}
                    />
                    {validationErrors[row.id]?.name && <p className='text-xs text-red-600'>{t('models.dialogs.batchCreate.required')}</p>}
                  </div>
                  <div className='min-w-32 flex-[3] space-y-1'>
                    <AutoCompleteSelect
                      selectedValue={row.icon}
                      onSelectedValueChange={(value) => {
                        handleIconChange(row.id, value);
                        clearValidationError(row.id, 'icon');
                      }}
                      items={iconOptions}
                      placeholder={t('models.fields.icon')}
                      emptyMessage={t('models.fields.noIcons')}
                      portalContainer={dialogContent}
                    />
                    {validationErrors[row.id]?.icon && <p className='text-xs text-red-600'>{t('models.dialogs.batchCreate.required')}</p>}
                  </div>
                  <Button
                    type='button'
                    variant='ghost'
                    size='icon'
                    className='h-8 w-8 flex-shrink-0'
                    onClick={() => handleRemoveRow(row.id)}
                    disabled={rows.length === 1}
                  >
                    <IconTrash className='h-4 w-4' />
                  </Button>
                </div>
              </div>
            ))}
          </div>
        </div>

        <div className='flex flex-shrink-0 flex-col gap-3 border-t pt-4'>
          <Button type='button' variant='outline' onClick={handleAddRow} disabled={rows.length >= MAX_ROWS}>
            <IconPlus className='mr-2 h-4 w-4' />
            {t('models.dialogs.batchCreate.addRow')} ({rows.length}/{MAX_ROWS})
          </Button>
          <div className='flex justify-end gap-2'>
            <Button type='button' variant='outline' onClick={handleClose}>
              {t('common.buttons.cancel')}
            </Button>
            <Button type='button' onClick={handleSubmit} disabled={bulkCreateModels.isPending}>
              {t('common.buttons.create')}
            </Button>
          </div>
        </div>
      </DialogContent>
    </Dialog>
  );
}
