import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import Timeline from '../components/Timeline';
import MovementBands from '../components/MovementBands';
import VirtualGallery from '../components/VirtualGallery';
import PaintingDetailView from '../components/PaintingDetail';
import ArtistBio from '../components/ArtistBio';
import CheckupPage from '../pages/CheckupPage';
import { api, type FixPaintingImageResult } from '../api/client';
import type { TimelineData, Artist, ArtistDetail, Painting, PaintingDetail } from '../types';
import { sortArtistPaintingsChronological } from '../utils/paintingUtils';
import { readDebugMode, writeDebugMode } from '../utils/debugMode';
import './HomePage.css';

type View =
  | { type: 'timeline' }
  | { type: 'checkup' }
  | { type: 'gallery'; artistId: number; data: ArtistDetail }
  | { type: 'painting'; paintingId: number; data: PaintingDetail; returnTo: View }
  | { type: 'bio'; artistId: number; data: ArtistDetail; returnTo: View };

function patchPaintingInArtistDetail(
  detail: ArtistDetail,
  paintingId: number,
  patch: Partial<Painting>
): ArtistDetail {
  return {
    ...detail,
    paintings: detail.paintings.map((p) => (p.id === paintingId ? { ...p, ...patch } : p)),
  };
}

export default function HomePage() {
  const [view, setView] = useState<View>({ type: 'timeline' });
  const [gallerySession, setGallerySession] = useState<{ artistId: number; data: ArtistDetail } | null>(
    null
  );
  const [bounds, setBounds] = useState({ min: -800, max: 2025 });
  const [viewStart, setViewStart] = useState(-800);
  const [viewEnd, setViewEnd] = useState(2025);
  const [timelineData, setTimelineData] = useState<TimelineData>({ eras: [], movements: [] });
  const [artists, setArtists] = useState<Artist[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [detailArtistPaintings, setDetailArtistPaintings] = useState<Painting[]>([]);
  const [imageRevisions, setImageRevisions] = useState<Record<number, number>>({});
  const [debugMode, setDebugMode] = useState(readDebugMode);
  const detailReturnToRef = useRef<View>({ type: 'timeline' });

  useEffect(() => {
    api.getBounds()
      .then((b) => {
        const min = b.min_year ?? -800;
        const max = b.max_year ?? 2025;
        setBounds({ min, max });
        setViewStart(min);
        setViewEnd(max);
      })
      .catch(() => {});
  }, []);

  useEffect(() => {
    if (view.type === 'gallery') {
      setGallerySession({ artistId: view.artistId, data: view.data });
    } else if (view.type === 'timeline') {
      setGallerySession(null);
    }
  }, [view]);

  const loadTimelineData = useCallback(async (start: number, end: number) => {
    try {
      setLoading(true);
      const [timeline, artistList] = await Promise.all([
        api.getTimeline(start, end),
        api.getArtists(start, end),
      ]);
      setTimelineData(timeline);
      setArtists(artistList);
      setError(null);
    } catch {
      setError('Could not load gallery data. Is the server running?');
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    loadTimelineData(viewStart, viewEnd);
  }, [viewStart, viewEnd, loadTimelineData]);

  const handleViewChange = (start: number, end: number) => {
    setViewStart(start);
    setViewEnd(end);
  };

  const toggleDebugMode = () => {
    setDebugMode((prev) => {
      const next = !prev;
      writeDebugMode(next);
      return next;
    });
  };

  const handlePaintingImageFixed = useCallback(async (paintingId: number, fixResult: FixPaintingImageResult) => {
    const data = await api.getPainting(paintingId);
    const patch: Partial<Painting> = {
      image_path: fixResult.imagePath ?? data.painting.image_path,
      thumbnail_path: fixResult.thumbnailPath ?? data.painting.thumbnail_path,
      checkup_checked: fixResult.checked ?? true,
      checkup_fixed: fixResult.fixed ?? true,
    };
    const updatedData: PaintingDetail = {
      ...data,
      painting: { ...data.painting, ...patch },
    };

    setImageRevisions((prev) => ({ ...prev, [paintingId]: (prev[paintingId] ?? 0) + 1 }));

    setView((current) => {
      if (current.type !== 'painting' || current.paintingId !== paintingId) return current;
      let returnTo = current.returnTo;
      if (returnTo.type === 'gallery' && returnTo.artistId === data.painting.artist_id) {
        returnTo = {
          ...returnTo,
          data: patchPaintingInArtistDetail(returnTo.data, paintingId, patch),
        };
      }
      return { ...current, data: updatedData, returnTo };
    });

    setDetailArtistPaintings((list) =>
      list.map((p) => (p.id === paintingId ? { ...p, ...patch } : p))
    );

    setGallerySession((session) =>
      session && session.artistId === data.painting.artist_id
        ? { ...session, data: patchPaintingInArtistDetail(session.data, paintingId, patch) }
        : session
    );
  }, []);

  const handlePaintingCheckupFlagsUpdated = useCallback(
    async (paintingId: number, flags: { checked: boolean; fixed: boolean }) => {
      const data = await api.getPainting(paintingId);
      const patch: Partial<Painting> = {
        checkup_checked: flags.checked,
        checkup_fixed: flags.fixed,
      };
      const updatedData: PaintingDetail = {
        ...data,
        painting: { ...data.painting, ...patch },
      };

      setView((current) => {
        if (current.type !== 'painting' || current.paintingId !== paintingId) return current;
        let returnTo = current.returnTo;
        if (returnTo.type === 'gallery' && returnTo.artistId === data.painting.artist_id) {
          returnTo = {
            ...returnTo,
            data: patchPaintingInArtistDetail(returnTo.data, paintingId, patch),
          };
        }
        return { ...current, data: updatedData, returnTo };
      });

      setDetailArtistPaintings((list) =>
        list.map((p) => (p.id === paintingId ? { ...p, ...patch } : p))
      );

      setGallerySession((session) =>
        session && session.artistId === data.painting.artist_id
          ? { ...session, data: patchPaintingInArtistDetail(session.data, paintingId, patch) }
          : session
      );
    },
    []
  );

  const handleArtistClick = async (artistId: number) => {
    try {
      const data = await api.getArtist(artistId);
      setGallerySession({ artistId, data });
      setView({ type: 'gallery', artistId, data });
    } catch {
      setError('Failed to load artist gallery.');
    }
  };

  const handlePaintingClick = async (paintingId: number) => {
    try {
      const data = await api.getPainting(paintingId);
      setView((prev) => {
        detailReturnToRef.current = prev;
        return {
          type: 'painting',
          paintingId,
          data,
          returnTo: prev,
        };
      });
    } catch {
      setError('Failed to load painting details.');
    }
  };

  const handleCatalogNavigate = useCallback(async (paintingId: number) => {
    const returnTo = detailReturnToRef.current;
    try {
      const data = await api.getPainting(paintingId);
      setView({
        type: 'painting',
        paintingId,
        data,
        returnTo,
      });
    } catch {
      setError('Failed to load painting details.');
    }
  }, []);

  const handleBioClick = (artistData: ArtistDetail, returnTo: View) => {
    setView({ type: 'bio', artistId: artistData.artist.id, data: artistData, returnTo });
  };

  useEffect(() => {
    if (view.type !== 'painting') {
      setDetailArtistPaintings([]);
      return;
    }

    const artistId = view.data.painting.artist_id;
    if (gallerySession?.artistId === artistId) {
      setDetailArtistPaintings(gallerySession.data.paintings);
      return;
    }

    let cancelled = false;
    api.getArtist(artistId)
      .then((data) => {
        if (!cancelled) setDetailArtistPaintings(data.paintings);
      })
      .catch(() => {
        if (!cancelled) setDetailArtistPaintings([]);
      });

    return () => {
      cancelled = true;
    };
  }, [view, gallerySession]);

  const sortedDetailArtistPaintings = useMemo(
    () => sortArtistPaintingsChronological(detailArtistPaintings),
    [detailArtistPaintings]
  );

  const galleryActive = view.type === 'gallery';

  return (
    <>
      {gallerySession && (
        <div className={galleryActive ? undefined : 'gallery-session-suspended'} aria-hidden={!galleryActive}>
          <VirtualGallery
            data={gallerySession.data}
            imageRevisions={imageRevisions}
            active={galleryActive}
            onPaintingClick={handlePaintingClick}
            onNavigateArtist={handleArtistClick}
            onBack={() => setView({ type: 'timeline' })}
            onBioClick={() => handleBioClick(gallerySession.data, { type: 'gallery', ...gallerySession })}
          />
        </div>
      )}

      {view.type === 'painting' && (
        <div className="home-overlay">
          <PaintingDetailView
            data={view.data}
            artistPaintings={sortedDetailArtistPaintings}
            onBack={() => {
              const returnTo = view.returnTo;
              if (returnTo.type === 'gallery' && gallerySession?.artistId === returnTo.artistId) {
                setView({
                  type: 'gallery',
                  artistId: gallerySession.artistId,
                  data: gallerySession.data,
                });
              } else {
                setView(returnTo);
              }
            }}
            onPaintingClick={handlePaintingClick}
            onCatalogNavigate={handleCatalogNavigate}
            onArtistBio={async () => {
              const artistData = await api.getArtist(view.data.painting.artist_id);
              setView({ type: 'bio', artistId: artistData.artist.id, data: artistData, returnTo: view });
            }}
            onInfluenceArtistClick={handleArtistClick}
            debugMode={debugMode}
            onPaintingImageFixed={handlePaintingImageFixed}
            onPaintingCheckupFlagsUpdated={handlePaintingCheckupFlagsUpdated}
          />
        </div>
      )}

      {view.type === 'bio' && (
        <div className="home-overlay">
          <ArtistBio
            artist={view.data.artist}
            onBack={() => setView(view.returnTo)}
            onEnterGallery={() =>
              setView({ type: 'gallery', artistId: view.artistId, data: view.data })
            }
          />
        </div>
      )}

      {view.type === 'checkup' && (
        <CheckupPage
          onBack={() => setView({ type: 'timeline' })}
          onOpenPainting={handlePaintingClick}
        />
      )}

      {view.type === 'timeline' && (
        <div className="home-page">
          <header className="site-header">
            <div className="site-dev-tools">
              <button
                type="button"
                className={`debug-mode-toggle${debugMode ? ' debug-mode-toggle-active' : ''}`}
                onClick={toggleDebugMode}
                title="Toggle developer image audit mode on painting details"
              >
                Debug mode{debugMode ? ': ON' : ''}
              </button>
              <button
                type="button"
                className="checkup-link-btn"
                onClick={() => setView({ type: 'checkup' })}
                title="Open painting image checkup table"
              >
                Checkup
              </button>
            </div>
            <h1>Virtual Art Gallery</h1>
            <p className="site-subtitle">Watch art movements branch forward through time — each flowing from what came before</p>
          </header>

          <Timeline
            eras={timelineData.eras}
            viewStart={viewStart}
            viewEnd={viewEnd}
            onViewChange={handleViewChange}
            absoluteMin={bounds.min}
            absoluteMax={bounds.max}
          />

          {error && <div className="error-banner">{error}</div>}

          {loading ? (
            <div className="loading home-movements-section">Loading art history...</div>
          ) : (
            <div className="home-movements-section">
              <MovementBands
                movements={timelineData.movements}
                artists={artists}
                viewStart={viewStart}
                viewEnd={viewEnd}
                absoluteMin={bounds.min}
                absoluteMax={bounds.max}
                onViewChange={handleViewChange}
                onArtistClick={handleArtistClick}
              />
            </div>
          )}
        </div>
      )}
    </>
  );
}
