import { useCallback, useEffect, useRef, useState, type ChangeEvent } from 'react';
import type { Artist } from '../types';
import {
  api,
  debugImageProxyUrl,
  portraitUrl,
  type DebugImageSearchResult,
  type DebugImageSearchResultItem,
  type FixArtistPortraitResult,
} from '../api/client';
import DebugSearchResultsModal from './DebugSearchResultsModal';
import '../components/PaintingDetail.css';
import './ArtistBio.css';

interface Props {
  artist: Artist & { movement_name?: string };
  debugMode?: boolean;
  debugShowMore?: boolean;
  portraitRevision?: number;
  onBack: () => void;
  onEnterGallery: () => void;
  onArtistPortraitFixed?: (
    artistId: number,
    fixResult: FixArtistPortraitResult
  ) => void | Promise<void>;
  onArtistCheckupFlagsUpdated?: (
    artistId: number,
    flags: { checked: boolean; fixed: boolean }
  ) => void | Promise<void>;
}

export default function ArtistBio({
  artist,
  debugMode = false,
  debugShowMore = false,
  portraitRevision = 0,
  onBack,
  onEnterGallery,
  onArtistPortraitFixed,
  onArtistCheckupFlagsUpdated,
}: Props) {
  const [debugSearch, setDebugSearch] = useState<DebugImageSearchResult | null>(null);
  const [debugLoading, setDebugLoading] = useState(false);
  const [debugError, setDebugError] = useState<string | null>(null);
  const [fixing, setFixing] = useState(false);
  const [markingChecked, setMarkingChecked] = useState(false);
  const [moreOpen, setMoreOpen] = useState(false);
  const [moreLoading, setMoreLoading] = useState(false);
  const [moreError, setMoreError] = useState<string | null>(null);
  const [moreResults, setMoreResults] = useState<Awaited<ReturnType<typeof api.getArtistDebugPortraitSearchMore>> | null>(null);
  const [applyingUrl, setApplyingUrl] = useState<string | null>(null);
  const [clearing, setClearing] = useState(false);
  const [uploading, setUploading] = useState(false);
  const uploadInputRef = useRef<HTMLInputElement>(null);

  const portraitCleared = !artist.portrait_path && !!artist.checkup_fixed;
  const showPortrait = !!artist.portrait_path || !artist.checkup_fixed;
  const portraitSrc = portraitUrl(artist.portrait_path, portraitRevision || undefined);

  const lifespan =
    artist.birth_year && artist.death_year
      ? `${artist.birth_year} – ${artist.death_year}`
      : artist.birth_year
        ? `b. ${artist.birth_year}`
        : '';

  useEffect(() => {
    if (!debugMode) {
      setDebugSearch(null);
      setDebugError(null);
      setMoreOpen(false);
      return;
    }

    let cancelled = false;
    setDebugLoading(true);
    setDebugError(null);
    setDebugSearch(null);

    api.getArtistDebugPortraitSearch(artist.id)
      .then((result) => {
        if (!cancelled) setDebugSearch(result);
      })
      .catch(() => {
        if (!cancelled) setDebugError('Portrait image search failed.');
      })
      .finally(() => {
        if (!cancelled) setDebugLoading(false);
      });

    return () => {
      cancelled = true;
    };
  }, [debugMode, artist.id, artist.name]);

  const applyPortraitUpdate = async (fixResult: FixArtistPortraitResult) => {
    if (onArtistPortraitFixed) {
      await onArtistPortraitFixed(artist.id, fixResult);
    }
  };

  const applyFixFromSearch = async (
    imageUrl: string,
    context: { searchUrl: string; source: string; thumbUrl?: string }
  ) => {
    const fixResult = await api.fixArtistPortrait(artist.id, imageUrl, context);
    await applyPortraitUpdate(fixResult);
    setDebugSearch((prev) =>
      prev
        ? { ...prev, imageUrl, thumbUrl: context.thumbUrl ?? prev.thumbUrl, source: context.source }
        : prev
    );
  };

  const handleFixPortrait = async () => {
    if (!debugSearch?.imageUrl || fixing) return;
    setFixing(true);
    setDebugError(null);
    try {
      await applyFixFromSearch(debugSearch.imageUrl, {
        searchUrl: debugSearch.searchUrl,
        source: debugSearch.source,
        thumbUrl: debugSearch.thumbUrl,
      });
    } catch (err) {
      setDebugError(err instanceof Error ? err.message : 'Could not replace portrait.');
    } finally {
      setFixing(false);
    }
  };

  const handleOpenMore = useCallback(async () => {
    setMoreOpen(true);
    setMoreLoading(true);
    setMoreError(null);
    setMoreResults(null);
    try {
      const results = await api.getArtistDebugPortraitSearchMore(artist.id);
      setMoreResults(results);
    } catch {
      setMoreError('Could not load search results.');
    } finally {
      setMoreLoading(false);
    }
  }, [artist.id]);

  useEffect(() => {
    if (!debugMode || !debugShowMore) return;
    void handleOpenMore();
  }, [debugMode, debugShowMore, artist.id, handleOpenMore]);

  const handleSelectMoreResult = async (item: DebugImageSearchResultItem) => {
    if (fixing || applyingUrl) return;
    setApplyingUrl(item.imageUrl);
    setMoreError(null);
    setDebugError(null);
    try {
      const searchUrl = moreResults?.searchUrl ?? debugSearch?.searchUrl ?? '';
      await applyFixFromSearch(item.imageUrl, {
        searchUrl,
        source: item.source,
        thumbUrl: item.thumbUrl,
      });
      setMoreOpen(false);
    } catch (err) {
      setMoreError(err instanceof Error ? err.message : 'Could not replace portrait.');
    } finally {
      setApplyingUrl(null);
    }
  };

  const handleMarkChecked = async () => {
    if (artist.checkup_checked || markingChecked) return;
    setMarkingChecked(true);
    setDebugError(null);
    try {
      const updated = await api.updateArtistCheckupFlags(artist.id, { checked: true });
      await onArtistCheckupFlagsUpdated?.(artist.id, updated);
    } catch (err) {
      setDebugError(err instanceof Error ? err.message : 'Could not mark as checked.');
    } finally {
      setMarkingChecked(false);
    }
  };

  const handleClearPortrait = async () => {
    if (clearing || fixing || uploading) return;
    setClearing(true);
    setDebugError(null);
    try {
      const result = await api.clearArtistPortrait(artist.id);
      await applyPortraitUpdate(result);
    } catch (err) {
      setDebugError(err instanceof Error ? err.message : 'Could not clear portrait.');
    } finally {
      setClearing(false);
    }
  };

  const handleUploadClick = () => {
    uploadInputRef.current?.click();
  };

  const handleUploadFile = async (e: ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    e.target.value = '';
    if (!file || uploading || fixing || clearing) return;
    setUploading(true);
    setDebugError(null);
    try {
      const result = await api.uploadArtistPortrait(artist.id, file);
      await applyPortraitUpdate(result);
    } catch (err) {
      setDebugError(err instanceof Error ? err.message : 'Could not upload portrait.');
    } finally {
      setUploading(false);
    }
  };

  return (
    <div className="artist-bio">
      <header className="bio-header">
        <button className="back-btn" onClick={onBack}>← Back</button>
        <h1>{artist.name}</h1>
        <button className="gallery-btn" onClick={onEnterGallery}>Enter Gallery</button>
      </header>

      <div className="bio-content">
        <div
          className={`bio-portrait${artist.checkup_checked ? ' bio-portrait-checked' : ''}${portraitCleared ? ' bio-portrait-empty' : ''}`}
        >
          {showPortrait ? (
            <img
              src={portraitSrc}
              alt={artist.name}
              onError={(e) => {
                (e.target as HTMLImageElement).src = '/placeholder-portrait.svg';
              }}
            />
          ) : null}
        </div>

        <div className="bio-text">
          <div className="bio-meta">
            {lifespan && <span className="bio-lifespan">{lifespan}</span>}
            {artist.movement_name && (
              <span className="bio-movement">{artist.movement_name}</span>
            )}
          </div>

          {artist.bio_short && (
            <p className="bio-summary">{artist.bio_short}</p>
          )}

          {artist.bio_full && (
            <div className="bio-full">
              {artist.bio_full.split('\n').map((para, i) => (
                <p key={i}>{para}</p>
              ))}
            </div>
          )}

          {!artist.bio_full && !artist.bio_short && (
            <p className="bio-empty">Biographical information not yet available.</p>
          )}

          {artist.wikipedia_title && (
            <p className="bio-source">
              Information sourced from Wikipedia article: {artist.wikipedia_title}
            </p>
          )}
        </div>
      </div>

      {debugMode && (
        <aside className="debug-image-panel" aria-label="Debug portrait search">
          <h4>{debugSearch?.sourceLabel ?? 'Portrait image search'}</h4>
          <p className="debug-image-query">
            {debugSearch?.query ?? `${artist.name} portrait`}
          </p>
          {debugLoading && <p className="debug-image-status">Searching…</p>}
          {debugError && <p className="debug-image-error">{debugError}</p>}
          {!debugLoading && debugSearch?.imageUrl && (
            <img
              className="debug-image-preview"
              src={debugImageProxyUrl(debugSearch.imageUrl, {
                searchUrl: debugSearch.searchUrl,
                source: debugSearch.source,
              })}
              alt={`Search result for ${debugSearch.query}`}
              onError={(e) => {
                (e.target as HTMLImageElement).src = '/placeholder-portrait.svg';
              }}
            />
          )}
          {!debugLoading && debugSearch && !debugSearch.imageUrl && !debugError && (
            <p className="debug-image-status">No portrait image result found.</p>
          )}
          <div className="debug-action-buttons">
            <button
              type="button"
              className="debug-checked-btn"
              onClick={handleMarkChecked}
              disabled={!!artist.checkup_checked || markingChecked}
            >
              {markingChecked ? '…' : 'Checked'}
            </button>
            <button
              type="button"
              className="debug-fix-btn"
              onClick={handleFixPortrait}
              disabled={fixing || debugLoading || !debugSearch?.imageUrl}
            >
              {fixing ? '…' : 'Fix it'}
            </button>
            <button
              type="button"
              className="debug-more-btn"
              onClick={handleOpenMore}
              disabled={debugLoading || moreLoading}
            >
              {moreLoading ? '…' : 'More'}
            </button>
          </div>
          <div className="debug-action-buttons debug-action-buttons-secondary">
            <button
              type="button"
              className="debug-clear-btn"
              onClick={handleClearPortrait}
              disabled={clearing || fixing || uploading || portraitCleared}
            >
              {clearing ? '…' : 'Clear'}
            </button>
            <button
              type="button"
              className="debug-upload-btn"
              onClick={handleUploadClick}
              disabled={uploading || fixing || clearing}
            >
              {uploading ? '…' : 'Upload'}
            </button>
            <input
              ref={uploadInputRef}
              type="file"
              accept="image/*"
              hidden
              onChange={handleUploadFile}
            />
          </div>
        </aside>
      )}

      <DebugSearchResultsModal
        open={moreOpen}
        title="Choose portrait"
        data={moreResults}
        loading={moreLoading}
        error={moreError}
        applyingUrl={applyingUrl}
        onClose={() => setMoreOpen(false)}
        onSelect={handleSelectMoreResult}
      />
    </div>
  );
}
