import { useState } from 'react';
import type { ChangeEvent } from 'react';
import type { Word } from '../types/vocabulary';

export type ImportPayload = Word[] | { words: Word[]; progress?: unknown[]; stats?: unknown };

interface ImportModalProps {
  isOpen: boolean;
  onClose: () => void;
  onImport: (payload: ImportPayload) => Promise<void> | void;
}

const normalizeWord = (input: Partial<Word>, index: number): Word | null => {
  const french = input.french?.trim();
  const english = input.english?.trim();

  if (!french || !english) {
    return null;
  }

  return {
    id: input.id || `imported-${Date.now()}-${index}`,
    french,
    english,
    pronunciation: input.pronunciation?.trim() || '',
    ttsText: input.ttsText?.trim() || french,
    chinese: input.chinese?.trim() || '',
    partOfSpeech: input.partOfSpeech?.trim() || '',
    example: input.example?.trim() || '',
    exampleTranslation: input.exampleTranslation?.trim() || '',
    examplePronunciation: input.examplePronunciation?.trim() || '',
    notes: input.notes?.trim() || '',
    audioUrl: input.audioUrl?.trim() || '',
    category: input.category?.trim() || 'General',
    difficulty: input.difficulty || 'beginner',
    tags: input.tags || [],
  };
};

const parseCsvLine = (line: string) => line.split(',').map((part) => part.trim().replace(/^"|"$/g, ''));

const parseTags = (value: string | undefined) =>
  value
    ?.split(/[|;]+/)
    .map((item) => item.trim())
    .filter(Boolean) || [];

export function ImportModal({ isOpen, onClose, onImport }: ImportModalProps) {
  const [content, setContent] = useState('');
  const [error, setError] = useState('');
  const [isImporting, setIsImporting] = useState(false);

  if (!isOpen) return null;

  const finishImport = async (payload: ImportPayload) => {
    setError('');
    setIsImporting(true);

    try {
      await onImport(payload);
      setContent('');
      onClose();
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Import failed. Please check the file format.');
    } finally {
      setIsImporting(false);
    }
  };

  const parseContent = async (text: string) => {
    try {
      const json = JSON.parse(text);

      if (Array.isArray(json)) {
        const words = json
          .map((item, index) => normalizeWord(item as Partial<Word>, index))
          .filter(Boolean) as Word[];

        if (words.length === 0) {
          throw new Error('The JSON word list is empty.');
        }

        await finishImport(words);
        return;
      }

      if (json && typeof json === 'object' && Array.isArray((json as { words?: unknown[] }).words)) {
        const backup = json as { words: Partial<Word>[]; progress?: unknown[]; stats?: unknown };
        const words = backup.words
          .map((item, index) => normalizeWord(item, index))
          .filter(Boolean) as Word[];

        if (words.length === 0) {
          throw new Error('The backup does not contain any valid words.');
        }

        await finishImport({
          words,
          progress: Array.isArray(backup.progress) ? backup.progress : undefined,
          stats: backup.stats,
        });
        return;
      }

      throw new Error('Unsupported JSON structure.');
    } catch (jsonError) {
      const lines = text
        .trim()
        .split(/\r?\n/)
        .map((line) => line.trim())
        .filter(Boolean);

      if (lines.length === 0) {
        throw jsonError instanceof Error ? jsonError : new Error('There is no importable content.');
      }

      const header = parseCsvLine(lines[0]).map((value) => value.toLowerCase());
      const hasHeader = header.includes('french') || header.includes('english');
      const dataLines = hasHeader ? lines.slice(1) : lines;

      const words = dataLines
        .map((line, index) => {
          const parts = parseCsvLine(line);

          if (hasHeader) {
            return normalizeWord(
              {
                french: parts[header.indexOf('french')] || '',
                english: parts[header.indexOf('english')] || '',
                chinese: parts[header.indexOf('chinese')] || '',
                pronunciation: parts[header.indexOf('pronunciation')] || '',
                ttsText: parts[header.indexOf('ttstext')] || '',
                partOfSpeech: parts[header.indexOf('partofspeech')] || '',
                category: parts[header.indexOf('category')] || 'General',
                example: parts[header.indexOf('example')] || '',
                exampleTranslation: parts[header.indexOf('exampletranslation')] || '',
                examplePronunciation: parts[header.indexOf('examplepronunciation')] || '',
                notes: parts[header.indexOf('notes')] || '',
                audioUrl: parts[header.indexOf('audiourl')] || '',
                difficulty: (parts[header.indexOf('difficulty')] as Word['difficulty']) || 'beginner',
                tags: parseTags(parts[header.indexOf('tags')]),
              },
              index,
            );
          }

          return normalizeWord(
            {
              french: parts[0] || '',
              english: parts[1] || '',
              pronunciation: parts[2] || '',
              category: parts[3] || 'General',
              difficulty: (parts[4] as Word['difficulty']) || 'beginner',
              chinese: parts[5] || '',
              example: parts[6] || '',
              exampleTranslation: parts[7] || '',
              tags: parseTags(parts[8]),
            },
            index,
          );
        })
        .filter(Boolean) as Word[];

      if (words.length === 0) {
        throw jsonError instanceof Error ? jsonError : new Error('Unable to parse the provided content.');
      }

      await finishImport(words);
    }
  };

  const handleFileUpload = async (event: ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = async (loadEvent) => {
      const text = String(loadEvent.target?.result || '');
      setContent(text);
      await parseContent(text);
    };
    reader.readAsText(file);
  };

  const handleSubmit = async () => {
    if (!content.trim()) {
      setError('Please paste content or choose a file first.');
      return;
    }

    await parseContent(content);
  };

  return (
    <div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 p-4">
      <div className="bg-white rounded-3xl shadow-2xl max-w-2xl w-full p-6">
        <h2 className="text-2xl font-bold text-gray-800 mb-2">Import vocabulary</h2>
        <p className="text-sm text-gray-500 mb-4">
          Supports CSV, JSON word lists, and full backup files with words, progress, and stats.
        </p>

        <div className="space-y-4">
          <div>
            <label className="block text-sm font-medium text-gray-600 mb-2">Upload a CSV or JSON file</label>
            <input
              type="file"
              accept=".csv,.json"
              onChange={handleFileUpload}
              className="w-full px-4 py-2 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500"
            />
          </div>

          <div className="relative">
            <div className="absolute inset-0 flex items-center">
              <div className="w-full border-t border-gray-200" />
            </div>
            <div className="relative flex justify-center text-sm">
              <span className="px-2 bg-white text-gray-500">or paste content</span>
            </div>
          </div>

          <textarea
            value={content}
            onChange={(event) => setContent(event.target.value)}
            placeholder={`CSV header example:
french,english,chinese,pronunciation,partOfSpeech,category,example,exampleTranslation,difficulty,tags
bonjour,hello,hello,bɔ̃ʒuʁ,interjection,Greetings,Bonjour tout le monde.,Hello everyone.,beginner,daily|greeting

JSON word list:
[{"french":"bonjour","english":"hello","category":"Greetings"}]

Full backup:
{"words":[...],"progress":[...],"stats":{...}}`}
            className="w-full h-56 px-4 py-3 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500 font-mono text-sm"
          />

          {error && <p className="text-red-500 text-sm">{error}</p>}

          <div className="flex gap-3 pt-2">
            <button
              onClick={onClose}
              className="flex-1 px-4 py-3 border border-gray-200 rounded-xl text-gray-600 hover:bg-gray-50 transition-colors"
            >
              Cancel
            </button>
            <button
              onClick={handleSubmit}
              disabled={isImporting}
              className="flex-1 px-4 py-3 bg-gradient-to-r from-blue-500 to-indigo-600 text-white rounded-xl hover:shadow-lg transition-all disabled:opacity-60"
            >
              {isImporting ? 'Importing...' : 'Import'}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}
