import { useEffect, useRef, 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';
import { InputNumber } from 'primereact/inputnumber';

function CoverThumb({ url, alt }) {
  const [failed, setFailed] = useState(false);
  useEffect(() => {
    setFailed(false);
  }, [url]);
  if (!url || failed) {
    return <div className="poster-thumb-lg poster-fallback">-</div>;
  }
  return (
    <img
      src={url}
      alt={alt}
      className="poster-thumb-lg"
      loading="eager"
      decoding="sync"
      onError={() => setFailed(true)}
    />
  );
}

const COVER_PRELOAD_TIMEOUT_MS = 3000;

function preloadCoverImage(url) {
  const src = String(url || '').trim();
  if (!src) {
    return Promise.resolve();
  }
  return new Promise((resolve) => {
    const image = new Image();
    let settled = false;
    const cleanup = () => {
      image.onload = null;
      image.onerror = null;
    };
    const done = () => {
      if (settled) {
        return;
      }
      settled = true;
      cleanup();
      resolve();
    };
    const timer = window.setTimeout(done, COVER_PRELOAD_TIMEOUT_MS);
    image.onload = () => {
      window.clearTimeout(timer);
      done();
    };
    image.onerror = () => {
      window.clearTimeout(timer);
      done();
    };
    image.src = src;
  });
}

export default function CdMetadataDialog({
  visible,
  context,
  onHide,
  onSubmit,
  onSearch,
  onFetchRelease,
  busy
}) {
  const [selected, setSelected] = useState(null);
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [searchBusy, setSearchBusy] = useState(false);
  const searchRunRef = useRef(0);

  // Manual metadata inputs
  const [manualTitle, setManualTitle] = useState('');
  const [manualArtist, setManualArtist] = useState('');
  const [manualYear, setManualYear] = useState(null);

  // Track titles are pre-filled from MusicBrainz and edited in the next step.
  const [trackTitles, setTrackTitles] = useState({});

  const tocTracks = Array.isArray(context?.tracks) ? context.tracks : [];

  const contextJobId = Number(context?.jobId || 0);

  useEffect(() => {
    if (!visible) {
      return;
    }
    setSelected(null);
    setQuery('');
    setManualTitle('');
    setManualArtist('');
    setManualYear(null);
    setResults([]);
    setSearchBusy(false);

    const titles = {};
    for (const t of tocTracks) {
      titles[t.position] = t.title || `Track ${t.position}`;
    }
    setTrackTitles(titles);
  }, [visible, contextJobId]);

  useEffect(() => {
    if (!selected) {
      return;
    }
    setManualTitle(selected.title || '');
    setManualArtist(selected.artist || '');
    setManualYear(selected.year || null);

    // Pre-fill track titles from the MusicBrainz result
    if (Array.isArray(selected.tracks) && selected.tracks.length > 0) {
      const titles = {};
      for (const t of selected.tracks) {
        if (t.position <= tocTracks.length) {
          titles[t.position] = t.title || `Track ${t.position}`;
        }
      }
      // Fill any remaining tracks not in MB result
      for (const t of tocTracks) {
        if (!titles[t.position]) {
          titles[t.position] = t.title || `Track ${t.position}`;
        }
      }
      setTrackTitles(titles);
    }
  }, [selected]);

  const handleSearch = async () => {
    const trimmedQuery = query.trim();
    if (!trimmedQuery) {
      return;
    }
    setSearchBusy(true);
    const searchRunId = searchRunRef.current + 1;
    searchRunRef.current = searchRunId;
    try {
      const searchResults = await onSearch(trimmedQuery);
      const normalizedResults = Array.isArray(searchResults) ? searchResults : [];
      await Promise.all(normalizedResults.map((item) => preloadCoverImage(item?.coverArtUrl)));
      if (searchRunRef.current !== searchRunId) {
        return;
      }
      setResults(normalizedResults);
      setSelected(null);
    } finally {
      if (searchRunRef.current === searchRunId) {
        setSearchBusy(false);
      }
    }
  };

  const handleSubmit = async () => {
    const normalizeTrackText = (value) => String(value || '').replace(/\s+/g, ' ').trim();
    let releaseDetails = selected;
    if (selected?.mbId && (!Array.isArray(selected?.tracks) || selected.tracks.length === 0) && typeof onFetchRelease === 'function') {
      const fetched = await onFetchRelease(selected.mbId);
      if (fetched && typeof fetched === 'object') {
        releaseDetails = fetched;
      }
    }

    const releaseTracks = Array.isArray(releaseDetails?.tracks) ? releaseDetails.tracks : [];
    const releaseTracksByPosition = new Map();
    releaseTracks.forEach((track, index) => {
      const parsedPosition = Number(track?.position);
      const normalizedPosition = Number.isFinite(parsedPosition) && parsedPosition > 0
        ? Math.trunc(parsedPosition)
        : index + 1;
      if (!releaseTracksByPosition.has(normalizedPosition)) {
        releaseTracksByPosition.set(normalizedPosition, track);
      }
    });

    const tracks = tocTracks.map((t, index) => {
      const position = Number(t.position);
      const byPosition = releaseTracksByPosition.get(position);
      const byIndex = releaseTracks[index];
      return {
        position,
        title: normalizeTrackText(
          byPosition?.title
          || byIndex?.title
          || trackTitles[t.position]
        ) || `Track ${t.position}`,
        artist: normalizeTrackText(
          byPosition?.artist
          || byIndex?.artist
          || manualArtist.trim()
          || releaseDetails?.artist
        ) || null,
        selected: true
      };
    });

    const payload = {
      jobId: context.jobId,
      title: manualTitle.trim() || context?.detectedTitle || 'Audio CD',
      artist: manualArtist.trim() || null,
      year: manualYear || null,
      mbId: releaseDetails?.mbId || selected?.mbId || null,
      coverUrl: releaseDetails?.coverArtUrl || selected?.coverArtUrl || null,
      tracks
    };

    await onSubmit(payload);
  };

  const mbTitleBody = (row) => (
    <div className="mb-result-row">
      <CoverThumb url={row.coverArtUrl} alt={row.title} />
      <div>
        <div><strong>{row.title}</strong></div>
        <small>{row.artist}{row.year ? ` | ${row.year}` : ''}</small>
        {row.label ? <small> | {row.label}</small> : null}
      </div>
    </div>
  );

  return (
    <Dialog
      header="CD-Metadaten auswählen"
      visible={visible}
      onHide={onHide}
      style={{ width: '58rem', maxWidth: '97vw' }}
      className="cd-metadata-dialog"
      breakpoints={{ '1200px': '92vw', '768px': '96vw', '560px': '98vw' }}
      modal
    >
      {/* MusicBrainz search */}
      <div className="search-row">
        <InputText
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          onKeyDown={(e) => e.key === 'Enter' && handleSearch()}
          placeholder="Album / Interpret suchen"
        />
        <Button
          label="MusicBrainz Suche"
          icon="pi pi-search"
          onClick={handleSearch}
          loading={busy || searchBusy}
        />
      </div>

      {results.length > 0 ? (
        <div className="table-scroll-wrap table-scroll-medium">
          <DataTable
            value={results}
            selectionMode="single"
            selection={selected}
            onSelectionChange={(e) => setSelected(e.value)}
            dataKey="mbId"
            size="small"
            scrollable
            scrollHeight="16rem"
            emptyMessage="Keine Treffer"
          >
            <Column header="Album" body={mbTitleBody} />
            <Column field="year" header="Jahr" style={{ width: '6rem' }} />
            <Column field="country" header="Land" style={{ width: '6rem' }} />
          </DataTable>
        </div>
      ) : null}

      {/* Manual metadata */}
      <h4 style={{ marginTop: '1rem', marginBottom: '0.5rem' }}>Metadaten</h4>
      <div className="metadata-grid">
        <InputText
          value={manualTitle}
          onChange={(e) => setManualTitle(e.target.value)}
          placeholder="Album-Titel"
        />
        <InputText
          value={manualArtist}
          onChange={(e) => setManualArtist(e.target.value)}
          placeholder="Interpret / Band"
        />
        <InputNumber
          value={manualYear}
          onValueChange={(e) => setManualYear(e.value)}
          placeholder="Jahr"
          useGrouping={false}
          min={1900}
          max={2100}
        />
      </div>

      {/* Track selection/editing moved to CD-Rip configuration panel */}
      {tocTracks.length > 0 ? (
        <small style={{ display: 'block', marginTop: '0.9rem' }}>
          {tocTracks.length} Tracks erkannt. Auswahl/Feinschliff (Checkboxen, Interpret, Titel, Länge) erfolgt im nächsten Schritt in der Job-Übersicht.
        </small>
      ) : null}

      <div className="dialog-actions" style={{ marginTop: '1rem' }}>
        <Button label="Abbrechen" severity="secondary" text onClick={onHide} />
        <Button
          label="Weiter"
          icon="pi pi-arrow-right"
          onClick={handleSubmit}
          loading={busy}
          disabled={!manualTitle.trim() && !context?.detectedTitle}
        />
      </div>
    </Dialog>
  );
}
