import { useEffect, useMemo, useState } from 'react';
import { Dialog } from 'primereact/dialog';
import { Button } from 'primereact/button';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { InputText } from 'primereact/inputtext';

export default function MetadataSelectionDialog({
  visible,
  context,
  onHide,
  onSubmit,
  onSearch,
  busy
}) {
  const parseDiscNumber = (rawValue) => {
    const text = String(rawValue ?? '').trim();
    if (!/^\d+$/.test(text)) {
      return null;
    }
    const parsed = Number(text);
    if (!Number.isFinite(parsed) || parsed <= 0) {
      return null;
    }
    return Math.trunc(parsed);
  };
  const [selected, setSelected] = useState(null);
  const [query, setQuery] = useState('');
  const [manualTitle, setManualTitle] = useState('');
  const [manualYear, setManualYear] = useState('');
  const [manualImdb, setManualImdb] = useState('');
  const [manualDiscNumber, setManualDiscNumber] = useState('');
  const [extraResults, setExtraResults] = useState([]);
  const [searchBusy, setSearchBusy] = useState(false);
  const [searchError, setSearchError] = useState('');
  const [submitError, setSubmitError] = useState('');
  const [seasonFilter, setSeasonFilter] = useState('');
  const [discValidationError, setDiscValidationError] = useState('');
  const metadataProvider = String(context?.metadataProvider || 'omdb').trim().toLowerCase() || 'omdb';
  const mediaProfile = String(
    context?.mediaProfile
    || context?.selectedMetadata?.mediaProfile
    || ''
  ).trim().toLowerCase();
  const providerLabel = metadataProvider === 'tmdb' ? 'TMDb' : 'OMDb';
  const supportsExternalIdInput = metadataProvider === 'omdb';
  const requiresDiscNumber = metadataProvider === 'tmdb' && (mediaProfile === 'dvd' || !mediaProfile);
  const effectiveDiscNumber = parseDiscNumber(manualDiscNumber);
  const hasValidDiscNumber = effectiveDiscNumber !== null;

  useEffect(() => {
    if (!visible) {
      return;
    }

    const selectedMetadata = context?.selectedMetadata || {};
    const defaultTitle = selectedMetadata.title || context?.detectedTitle || '';
    const defaultYear = selectedMetadata.year ? String(selectedMetadata.year) : '';
    const defaultImdb = selectedMetadata.imdbId || '';

    setSelected(null);
    setQuery(defaultTitle);
    setManualTitle(defaultTitle);
    setManualYear(defaultYear);
    setManualImdb(defaultImdb);
    setManualDiscNumber('');
    setExtraResults([]);
    setSearchBusy(false);
    setSearchError('');
    setSubmitError('');
    setSeasonFilter('');
    setDiscValidationError('');
  }, [visible, context]);

  useEffect(() => {
    if (!discValidationError) {
      return;
    }
    if (!requiresDiscNumber || hasValidDiscNumber) {
      setDiscValidationError('');
    }
  }, [discValidationError, requiresDiscNumber, hasValidDiscNumber]);

  useEffect(() => {
    if (submitError) {
      setSubmitError('');
    }
  }, [manualDiscNumber, seasonFilter, selected]);

  const rows = useMemo(() => {
    const base = Array.isArray(context?.metadataCandidates)
      ? context.metadataCandidates
      : (context?.omdbCandidates || []);
    const all = [...base, ...extraResults];
    const map = new Map();

    all.forEach((item) => {
      const rowKey = String(
        item?.providerId
        || item?.imdbId
        || item?.tmdbId
        || `${item?.title || '-'}::${item?.year || '-'}::${item?.seasonNumber || '-'}`
      ).trim();
      if (!rowKey) {
        return;
      }
      map.set(rowKey, {
        ...item,
        _metadataKey: rowKey
      });
    });

    return Array.from(map.values());
  }, [context, extraResults]);

  const filteredRows = useMemo(() => {
    if (metadataProvider !== 'tmdb') {
      return rows;
    }
    const normalizedFilter = String(seasonFilter || '').trim().toLowerCase();
    if (!normalizedFilter) {
      return rows;
    }
    return rows.filter((row) => {
      const seasonNo = String(row?.seasonNumber ?? '').trim().toLowerCase();
      const seasonName = String(row?.seasonName || '').trim().toLowerCase();
      return seasonNo.includes(normalizedFilter) || seasonName.includes(normalizedFilter);
    });
  }, [metadataProvider, rows, seasonFilter]);

  const titleWithPosterBody = (row) => (
    <div className="omdb-row">
      {row.poster && row.poster !== 'N/A' ? (
        <img src={row.poster} alt={row.title} className="poster-thumb-lg" />
      ) : (
        <div className="poster-thumb-lg poster-fallback">-</div>
      )}
      <div>
        <div><strong>{row.title}</strong></div>
        <small>
          {row.year || '-'}
          {row.seasonNumber ? ` | Staffel ${row.seasonNumber}` : ''}
          {row.seasonName ? ` | ${row.seasonName}` : ''}
          {row.episodeCount ? ` | ${row.episodeCount} Episoden` : ''}
          {row.imdbId ? ` | ${row.imdbId}` : ''}
          {!row.imdbId && row.tmdbId ? ` | TMDb ${row.tmdbId}` : ''}
        </small>
      </div>
    </div>
  );

  const handleSearch = async () => {
    const trimmedQuery = String(query || '').trim();
    if (!trimmedQuery || typeof onSearch !== 'function') {
      return;
    }
    setSearchBusy(true);
    setSearchError('');
    try {
      const results = await onSearch(trimmedQuery, {
        metadataProvider
      });
      setExtraResults(Array.isArray(results) ? results : []);
    } catch (error) {
      setExtraResults([]);
      setSearchError(error?.message || 'Suche fehlgeschlagen.');
    } finally {
      setSearchBusy(false);
    }
  };

  const handleSubmit = async () => {
    setDiscValidationError('');
    setSubmitError('');
    if (requiresDiscNumber && !hasValidDiscNumber) {
      setDiscValidationError('Disk-Nummer ist Pflicht und muss eine ganze Zahl >= 1 sein.');
      return;
    }

    const payload = selected
      ? {
          jobId: context.jobId,
          title: selected.title,
          year: selected.year,
          imdbId: selected.imdbId,
          poster: selected.poster && selected.poster !== 'N/A' ? selected.poster : null,
          fromOmdb: metadataProvider === 'omdb',
          metadataProvider,
          providerId: selected.providerId || null,
          tmdbId: selected.tmdbId || null,
          metadataKind: selected.metadataKind || null,
          seasonNumber: selected.seasonNumber || null,
          seasonName: selected.seasonName || null,
          episodeCount: selected.episodeCount || 0,
          episodes: Array.isArray(selected.episodes) ? selected.episodes : [],
          ...(effectiveDiscNumber ? { discNumber: effectiveDiscNumber } : {})
        }
      : {
          jobId: context.jobId,
          title: manualTitle,
          year: manualYear,
          imdbId: supportsExternalIdInput ? manualImdb : null,
          poster: null,
          fromOmdb: false,
          metadataProvider,
          seasonNumber: null,
          ...(effectiveDiscNumber ? { discNumber: effectiveDiscNumber } : {})
        };

    try {
      await onSubmit(payload);
    } catch (error) {
      const details = Array.isArray(error?.details) ? error.details : [];
      const hasDuplicateDiscError = details.some((detail) => String(detail?.code || '').trim().toUpperCase() === 'SERIES_DISC_ALREADY_EXISTS');
      const message = String(error?.message || 'Metadaten konnten nicht uebernommen werden.').trim() || 'Metadaten konnten nicht uebernommen werden.';
      if (hasDuplicateDiscError) {
        setSubmitError(message);
        return;
      }
      setSubmitError(message);
    }
  };

  const handleHideRequest = () => {
    if (requiresDiscNumber && !hasValidDiscNumber) {
      setDiscValidationError('Disk-Nummer ist Pflicht und muss eine ganze Zahl >= 1 sein.');
      return;
    }
    onHide?.();
  };

  return (
    <Dialog
      header="Metadaten auswählen"
      visible={visible}
      onHide={handleHideRequest}
      style={{ width: '52rem', maxWidth: '95vw' }}
      className="metadata-selection-dialog"
      breakpoints={{ '1200px': '92vw', '768px': '96vw', '560px': '98vw' }}
      modal
    >
      <div className="search-row">
        <InputText
          value={query}
          onChange={(event) => setQuery(event.target.value)}
          onKeyDown={(event) => {
            if (event.key === 'Enter') {
              event.preventDefault();
              void handleSearch();
            }
          }}
          placeholder="Titel suchen"
        />
        <Button label={`${providerLabel} Suche`} icon="pi pi-search" onClick={handleSearch} loading={searchBusy} disabled={searchBusy || busy} />
      </div>
      <div className={`metadata-filter-grid${metadataProvider !== 'tmdb' ? ' metadata-filter-grid-single' : ''}`}>
        {metadataProvider === 'tmdb' ? (
          <InputText
            value={seasonFilter}
            onChange={(event) => setSeasonFilter(event.target.value)}
            placeholder="Staffel-Filter (optional, z.B. 1 oder 5.2)"
            disabled={searchBusy || busy}
          />
        ) : null}
        <div className="metadata-filter-disc">
          <InputText
            value={manualDiscNumber}
            onChange={(event) => setManualDiscNumber(event.target.value)}
            placeholder={requiresDiscNumber ? 'Disc-Nr (Pflicht)' : 'Disc-Nr (optional)'}
            inputMode="numeric"
            disabled={searchBusy || busy}
          />
          <small className="metadata-filter-subtitle">
            {requiresDiscNumber
              ? 'Pflichtfeld fuer Serien-DVDs. Ohne Disk-Nummer koennen die Metadaten nicht verlassen werden.'
              : 'Optionale Disc-Nummer fuer internes Mapping und Output-Templates. Nur Werte groesser 0 werden gespeichert.'}
          </small>
        </div>
      </div>
      {searchError ? <small className="error-text">{searchError}</small> : null}
      {discValidationError ? <small className="error-text">{discValidationError}</small> : null}
      {submitError ? <small className="error-text">{submitError}</small> : null}

      <div className="table-scroll-wrap table-scroll-medium">
        <DataTable
          value={filteredRows}
          selectionMode="single"
          selection={selected}
          onSelectionChange={(event) => setSelected(event.value)}
          dataKey="_metadataKey"
          size="small"
          scrollable
          scrollHeight="22rem"
          emptyMessage="Keine Treffer"
          responsiveLayout="stack"
          breakpoint="960px"
        >
          <Column header="Titel" body={titleWithPosterBody} />
          <Column field="year" header="Jahr" style={{ width: '8rem' }} />
          <Column
            header={metadataProvider === 'tmdb' ? 'Staffel' : 'IMDb'}
            body={(row) => (metadataProvider === 'tmdb'
              ? (row.seasonNumber ? `S${row.seasonNumber}` : '-')
              : (row.imdbId || '-'))}
            style={{ width: '10rem' }}
          />
        </DataTable>
      </div>

      <h4>Manuelle Eingabe</h4>
      <div className="metadata-grid">
        <InputText
          value={manualTitle}
          onChange={(event) => setManualTitle(event.target.value)}
          placeholder="Titel"
          disabled={!!selected}
        />
        <InputText
          value={manualYear}
          onChange={(event) => setManualYear(event.target.value)}
          placeholder="Jahr"
          disabled={!!selected}
        />
        <InputText
          value={manualImdb}
          onChange={(event) => setManualImdb(event.target.value)}
          placeholder={supportsExternalIdInput ? 'IMDb-ID' : 'Externe ID'}
          disabled={!!selected || !supportsExternalIdInput}
        />
      </div>

      <div className="dialog-actions">
        <Button
          label="Abbrechen"
          severity="secondary"
          text
          onClick={handleHideRequest}
          disabled={requiresDiscNumber && !hasValidDiscNumber}
        />
        <Button
          label="Auswahl übernehmen"
          icon="pi pi-play"
          onClick={handleSubmit}
          loading={busy}
          disabled={
            (!selected && !manualTitle.trim() && !manualImdb.trim())
            || (requiresDiscNumber && !hasValidDiscNumber)
          }
        />
      </div>
    </Dialog>
  );
}
