// #region Translate.DictionaryDetailModel [C:4] [TYPE Model] [SEMANTICS translate,dictionary,entry,crud,import,model]
// @ingroup Translate
// @BRIEF Screen model for dictionary detail page — manages entry list, CRUD operations, and CSV import.
// @INVARIANT Expanding an entry clears previous expanded state.
// @INVARIANT Import preview is cleared when import form is closed.
// @STATE loading | editing | importing | import_preview | import_conflict | saving
// @ACTION loadDictionary() / loadEntries() — Fetch data.
// @ACTION saveEntry() / addEntry() / deleteEntry() — CRUD.
// @ACTION importDictionary() / previewImport() — Import flow.
// @RELATION DEPENDS_ON -> [ApiModule]
// @RELATION CALLS -> [CotLogger]

import { api } from '$lib/api.js';
import { addToast } from '$lib/toasts.svelte.js';
import { t } from '$lib/i18n/index.svelte.js';
import { ALL_LANGUAGES } from '$lib/i18n/languages.js';
import { SvelteURLSearchParams } from "svelte/reactivity";

type AppState = 'idle' | 'loading' | 'editing' | 'importing' | 'import_preview' | 'import_conflict' | 'saving';

interface DictionaryEntry {
  id: string;
  source_term: string;
  target_term: string;
  source_language?: string;
  target_language?: string;
  context_notes?: string;
  context_data?: unknown;
  usage_notes?: string;
  is_regex?: boolean;
}

interface EditForm {
  source_term: string;
  target_term: string;
  source_language: string;
  target_language: string;
  context_notes: string;
  context_data: unknown;
  usage_notes: string;
  is_regex: boolean;
}

interface ImportResult {
  imported?: number;
  skipped?: number;
  errors?: string[];
}

export class DictionaryDetailModel {
  // ── Dictionary data ───────────────────────────────────────────
  dictionary: Record<string, unknown> | null = $state(null);
  entries: DictionaryEntry[] = $state([]);
  totalEntries: number = $state(0);
  entryPage: number = $state(1);
  appState: AppState = $state('loading');

  // ── Edit ──────────────────────────────────────────────────────
  editEntryId: string | null = $state(null);
  editForm: EditForm = $state({ source_term: '', target_term: '', source_language: '', target_language: '', context_notes: '', context_data: null, usage_notes: '', is_regex: false });
  editContextDataRaw: string = $state('');

  // ── Add new ───────────────────────────────────────────────────
  showAddForm: boolean = $state(false);
  addForm: { source_term: string; target_term: string; source_language: string; target_language: string; context_notes: string; is_regex: boolean } = $state({ source_term: '', target_term: '', source_language: 'und', target_language: 'und', context_notes: '', is_regex: false });
  isAdding: boolean = $state(false);

  // ── Expand (view detail) ──────────────────────────────────────
  expandedEntryId: string | null = $state(null);
  expandedEditing: boolean = $state(false);
  expandedContextData: string = $state('');
  expandedUsageNotes: string = $state('');

  // ── Import ────────────────────────────────────────────────────
  showImportForm: boolean = $state(false);
  importContent: string = $state('');
  importDelimiter: string = $state('');
  importOnConflict: string = $state('overwrite');
  importPreview: unknown[] = $state([]);
  importErrors: string[] = $state([]);
  importResult: ImportResult | null = $state(null);
  isImporting: boolean = $state(false);

  // ── Filter ────────────────────────────────────────────────────
  filterSourceLanguage: string = $state('');

  // ── Context ───────────────────────────────────────────────────
  dictionaryId: string = $state('');
  allowedLanguages: string[] = $state([]);

  // ── Derived ───────────────────────────────────────────────────
  isLoading = $derived(this.appState === 'loading');
  isEditing = $derived(this.appState === 'editing');
  isSaving = $derived(this.appState === 'saving');

  /** Language options for selects, filtered by allowed_languages (fallback to all). */
  languageOptions = $derived(
    (this.allowedLanguages.length > 0 ? ALL_LANGUAGES.filter(l => this.allowedLanguages.includes(l.code)) : ALL_LANGUAGES)
  );

  // ── Actions ───────────────────────────────────────────────────

  async loadAllowedLanguages(): Promise<void> {
    try {
      this.allowedLanguages = await api.getAllowedLanguages() || [];
    } catch {
      // Non-critical: fall back to full list
      this.allowedLanguages = [];
    }
  }

  async loadDictionary(): Promise<void> {
    if (!this.dictionaryId) return;
    this.appState = 'loading';
    try {
      this.dictionary = await api.requestApi(`/translate/dictionaries/${this.dictionaryId}`) as Record<string, unknown>;
      this.appState = 'idle';
      this.loadAllowedLanguages();
      this.loadEntries();
    } catch (e: unknown) {
      addToast(e instanceof Error ? e.message : 'Failed to load dictionary', 'error');
      this.appState = 'idle';
    }
  }

  async loadEntries(): Promise<void> {
    if (!this.dictionaryId) return;
    try {
      const params = new SvelteURLSearchParams({ page: String(this.entryPage), page_size: '50' });
      if (this.filterSourceLanguage) params.append('source_language', this.filterSourceLanguage);
      const res = await api.requestApi(`/translate/dictionaries/${this.dictionaryId}/entries?${params}`) as { items?: DictionaryEntry[]; entries?: DictionaryEntry[]; total?: number };
      this.entries = (res.items || res.entries || []) as DictionaryEntry[];
      this.totalEntries = res.total || 0;
    } catch (e: unknown) {
      addToast(e instanceof Error ? e.message : 'Failed to load entries', 'error');
    }
  }

  startEdit(entry: DictionaryEntry): void {
    this.editEntryId = entry.id;
    this.editForm = { source_term: entry.source_term, target_term: entry.target_term, source_language: entry.source_language || '', target_language: entry.target_language || '', context_notes: entry.context_notes || '', context_data: entry.context_data, usage_notes: entry.usage_notes || '', is_regex: entry.is_regex || false };
    this.editContextDataRaw = entry.context_data ? JSON.stringify(entry.context_data, null, 2) : '';
    this.appState = 'editing';
  }

  cancelEdit(): void {
    this.editEntryId = null;
    this.appState = 'idle';
  }

  async saveEntry(): Promise<void> {
    if (!this.editEntryId) return;
    this.appState = 'saving';
    try {
      const payload = { ...this.editForm };
      if (this.editContextDataRaw) {
        try { payload.context_data = JSON.parse(this.editContextDataRaw); } catch { /* keep as string */ }
      }
      await api.requestApi(`/translate/dictionaries/${this.dictionaryId}/entries/${this.editEntryId}`, 'PUT', payload);
      addToast(t.translate?.dictionaries?.entry_saved || 'Entry saved', 'success');
      this.cancelEdit();
      this.loadEntries();
    } catch (e: unknown) {
      addToast(e instanceof Error ? e.message : 'Failed to save entry', 'error');
      this.appState = 'editing';
    }
  }

  async addEntry(): Promise<void> {
    this.isAdding = true;
    try {
      await api.requestApi(`/translate/dictionaries/${this.dictionaryId}/entries`, 'POST', this.addForm);
      addToast(t.translate?.dictionaries?.entry_added || 'Entry added', 'success');
      this.showAddForm = false;
      this.addForm = { source_term: '', target_term: '', source_language: 'und', target_language: 'und', context_notes: '', is_regex: false };
      this.loadEntries();
    } catch (e: unknown) {
      addToast(e instanceof Error ? e.message : 'Failed to add entry', 'error');
    } finally { this.isAdding = false; }
  }

  async deleteEntry(entryId: string): Promise<void> {
    if (!confirm(t.translate?.dictionaries?.confirm_delete || 'Delete this entry?')) return;
    try {
      await api.requestApi(`/translate/dictionaries/${this.dictionaryId}/entries/${entryId}`, 'DELETE');
      addToast(t.translate?.dictionaries?.entry_deleted || 'Entry deleted', 'success');
      this.loadEntries();
    } catch (e: unknown) {
      addToast(e instanceof Error ? e.message : 'Failed to delete entry', 'error');
    }
  }

  toggleExpand(entryId: string): void {
    if (this.expandedEntryId === entryId) { this.expandedEntryId = null; return; }
    this.expandedEntryId = entryId;
    this.expandedEditing = false;
  }

  async previewImport(): Promise<void> {
    if (!this.importContent) return;
    this.appState = 'importing';
    try {
      const res = await api.requestApi(`/translate/dictionaries/${this.dictionaryId}/import`, 'POST', { content: this.importContent, delimiter: this.importDelimiter || undefined, on_conflict: this.importOnConflict, preview: true }) as { preview?: unknown[]; errors?: string[] };
      this.importPreview = (res.preview || []) as unknown[];
      this.importErrors = (res.errors || []) as string[];
      this.appState = 'import_preview';
    } catch (e: unknown) {
      addToast(e instanceof Error ? e.message : 'Preview failed', 'error');
      this.appState = 'idle';
    }
  }

  async executeImport(): Promise<void> {
    this.isImporting = true;
    try {
      const res = await api.requestApi(`/translate/dictionaries/${this.dictionaryId}/import`, 'POST', { content: this.importContent, delimiter: this.importDelimiter || undefined, on_conflict: this.importOnConflict }) as ImportResult;
      this.importResult = res;
      this.showImportForm = false;
      this.loadEntries();
      addToast(t.translate?.dictionaries?.import_success || `Imported ${res.imported || 0} entries`, 'success');
    } catch (e: unknown) {
      addToast(e instanceof Error ? e.message : 'Import failed', 'error');
    } finally { this.isImporting = false; }
  }
}
// #endregion Translate.DictionaryDetailModel
