// Fix: Refactored component rendering from `React.createElement` to JSX syntax.
// This resolves TypeScript errors related to incorrect prop type inference for
// DOM elements and improves code readability and maintainability.

import React, { useState, useMemo, useEffect, useCallback } from 'react';
import { createRoot } from 'react-dom/client';

// --- TYPE DEFINITIONS ---
type Photo = {
  id: number;
  src: string;
  title: string;
  date: string;
  cycle: string;
  description: string;
  technique: string;
  dimensions: string;
  tags: string[];
};

type Filters = {
    cycle: string[];
    year: number[];
    searchTerm: string;
};

type SortOrder = 'random' | 'date-desc' | 'date-asc' | 'cycle-asc' | 'cycle-desc' | 'size-desc' | 'size-asc';


// --- DATA STRUCTURE ---
const navItems = [
  { id: 'portfolio', title: 'Portfolio' },
  { id: 'bio', title: 'Biografia' },
  { id: 'exhibitions', title: 'Wystawy' },
  { id: 'contact', title: 'Kontakt' }
] as const;

type PageName = typeof navItems[number]['id'];

// --- UTILITY FUNCTIONS ---
const shuffleArray = (array: Photo[]): Photo[] => {
  const newArr = [...array];
  for (let i = newArr.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [newArr[i], newArr[j]] = [newArr[j], newArr[i]];
  }
  return newArr;
};

const parseDimensions = (dimString: string): number => {
    if (!dimString || typeof dimString !== 'string') return 0;
    const parts = dimString.toLowerCase().replace(/cm/g, '').split('x');
    if (parts.length !== 2) return 0;
    const width = parseFloat(parts[0]);
    const height = parseFloat(parts[1]);
    if (isNaN(width) || isNaN(height)) return 0;
    return width * height;
};


// --- COMPONENTS ---

const Carousel = ({ images }: { images: string[] }) => {
    const [currentIndex, setCurrentIndex] = useState(0);

    const goToNext = useCallback(() => {
        setCurrentIndex(prevIndex => (prevIndex === images.length - 1 ? 0 : prevIndex + 1));
    }, [images.length]);

    const goToPrevious = () => {
        setCurrentIndex(prevIndex => (prevIndex === 0 ? images.length - 1 : prevIndex - 1));
    };

    useEffect(() => {
        const timer = setInterval(() => {
            goToNext();
        }, 5000); // Zmień slajd co 5 sekund
        return () => clearInterval(timer);
    }, [goToNext]);

    if (!images || images.length === 0) {
        return null;
    }

    return (
        <div className="carousel-container" aria-roledescription="carousel">
            <div className="carousel-slider" style={{ transform: `translateX(-${currentIndex * 100}%)` }}>
                {images.map((src, index) => (
                    <div className="carousel-slide" key={index} aria-hidden={currentIndex !== index}>
                        <img src={src} alt={`Slajd ${index + 1}`} loading="lazy" />
                    </div>
                ))}
            </div>
            <button onClick={goToPrevious} className="carousel-btn carousel-prev" aria-label="Poprzedni slajd">❮</button>
            <button onClick={goToNext} className="carousel-btn carousel-next" aria-label="Następny slajd">❯</button>
        </div>
    );
};

type HeaderProps = {
    currentPage: PageName;
    setCurrentPage: React.Dispatch<React.SetStateAction<PageName>>;
};

const Header = ({ currentPage, setCurrentPage }: HeaderProps) => (
  <header>
    <div className="container">
      <h1 onClick={() => setCurrentPage('portfolio')}>MAREK PRZYBYŁ</h1>
      <nav>
        <ul>
          {navItems.map(item => (
            <li key={item.id}>
              <button
                className={currentPage === item.id ? 'active' : ''}
                onClick={() => setCurrentPage(item.id)}
              >
                {item.title}
              </button>
            </li>
          ))}
        </ul>
      </nav>
    </div>
  </header>
);

type SortControlsProps = {
    sortOrder: SortOrder;
    setSortOrder: React.Dispatch<React.SetStateAction<SortOrder>>;
};

const SortControls = ({ sortOrder, setSortOrder }: SortControlsProps) => (
  <div className="sort-controls-inner">
    <select
      id="sort-select"
      value={sortOrder}
      onChange={(e) => setSortOrder(e.target.value as SortOrder)}
    >
      <option value="random">Losowo</option>
      <option value="date-desc">Data (od najnowszych)</option>
      <option value="date-asc">Data (od najstarszych)</option>
      <option value="cycle-asc">Cykl (A-Z)</option>
      <option value="cycle-desc">Cykl (Z-A)</option>
      <option value="size-desc">Wymiary (od największych)</option>
      <option value="size-asc">Wymiary (od najmniejszych)</option>
    </select>
  </div>
);

type FilterPanelProps = {
    photos: Photo[];
    activeFilters: Filters;
    setFilters: React.Dispatch<React.SetStateAction<Filters>>;
    sortOrder: SortOrder;
    setSortOrder: React.Dispatch<React.SetStateAction<SortOrder>>;
};

const FilterPanel = ({ photos, activeFilters, setFilters, sortOrder, setSortOrder }: FilterPanelProps) => {
  const [isCollapsed, setIsCollapsed] = useState(true);
  const cycles = useMemo(() => [...new Set(photos.map(p => p.cycle))], [photos]);
  const years = useMemo(() => [...new Set(photos.map(p => new Date(p.date).getFullYear()))].sort((a: number, b: number) => b - a), [photos]);

  const handleFilterClick = (type: 'cycle' | 'year', value: string | number, e: React.MouseEvent) => {
    const ctrlPressed = e.ctrlKey || e.metaKey; // metaKey for Mac support
    setFilters(prev => {
        const newFilters = { ...prev };
        const currentFilterValues = prev[type] as (string | number)[];

        if (ctrlPressed) {
            const newValues = currentFilterValues.includes(value)
                ? currentFilterValues.filter(v => v !== value)
                : [...currentFilterValues, value];
            newFilters[type] = newValues as any;
        } else {
            const isOnlyOneSelected = currentFilterValues.length === 1 && currentFilterValues[0] === value;
            newFilters[type] = isOnlyOneSelected ? [] : [value] as any;
        }
        return newFilters;
    });
  };
  
  const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setFilters(prev => ({ ...prev, searchTerm: e.target.value, cycle: prev.cycle, year: prev.year }));
  };

  const clearFilters = () => setFilters({ cycle: [], year: [], searchTerm: '' });

  return (
    <aside className={`filter-panel ${isCollapsed ? 'collapsed' : ''}`}>
      <button className="toggle-filters-btn" onClick={() => setIsCollapsed(!isCollapsed)}>
        Filtry i sortowanie {isCollapsed ? '▼' : '▲'}
      </button>
      <div className="filters-content-wrapper">
        <div className="filter-group">
          <h3>Wyszukaj</h3>
          <input 
            type="text" 
            placeholder="np. portret, 2023, miasto..."
            value={activeFilters.searchTerm || ''}
            onChange={handleSearchChange}
            className="search-input"
          />
        </div>
        <div className="filter-group">
          <h3>Cykle</h3>
          <ul>
            {cycles.map(cycle => (
              <li key={cycle}>
                <button
                  className={activeFilters.cycle.includes(cycle) ? 'active' : ''}
                  onClick={(e) => handleFilterClick('cycle', cycle, e)}
                >
                  {cycle}
                </button>
              </li>
            ))}
          </ul>
        </div>
        <div className="filter-group">
          <h3>Rok</h3>
          <ul>
            {years.map(year => (
              <li key={year}>
                <button
                  className={activeFilters.year.includes(year) ? 'active' : ''}
                  onClick={(e) => handleFilterClick('year', Number(year), e)}
                >
                  {year}
                </button>
              </li>
            ))}
          </ul>
        </div>
        <div className="filter-group">
          <h3>Sortuj</h3>
          <SortControls sortOrder={sortOrder} setSortOrder={setSortOrder} />
        </div>
        {(activeFilters.cycle.length > 0 || activeFilters.year.length > 0 || activeFilters.searchTerm) &&
          <button onClick={clearFilters} className="clear-filters-btn">Wyczyść filtry</button>
        }
      </div>
    </aside>
  );
};

type PhotoGridProps = {
    photos: Photo[];
    onPhotoClick: (index: number) => void;
};

const PhotoGrid = ({ photos, onPhotoClick }: PhotoGridProps) => (
  <div className="photo-grid">
    {photos.map((photo, index) => (
      <div key={photo.id} className="photo-item" onClick={() => onPhotoClick(index)}>
        <img src={photo.src} alt={photo.title} loading="lazy" />
        <div className="photo-title-overlay">{photo.title}</div>
      </div>
    ))}
  </div>
);

type LightboxProps = {
    photos: Photo[];
    activeIndex: number | null;
    onClose: () => void;
    onNavigate: (direction: number) => void;
};

const Lightbox = ({ photos, activeIndex, onClose, onNavigate }: LightboxProps) => {
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'Escape') onClose();
      if (e.key === 'ArrowLeft') onNavigate(-1);
      if (e.key === 'ArrowRight') onNavigate(1);
    };
    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [onClose, onNavigate]);

  if (activeIndex === null || !photos[activeIndex]) return null;

  const photo = photos[activeIndex];

  return (
    <div className="lightbox-overlay" onClick={onClose}>
      <div className="lightbox-content" onClick={(e: React.MouseEvent) => e.stopPropagation()}>
        <img src={photo.src} alt={photo.title} />
        <aside className="lightbox-details">
          <h3>{photo.title}</h3>
          <p> 
            <strong>Rok</strong>
            {' '}{new Date(photo.date).getFullYear()}
          </p>
          {photo.description && <p> 
            <strong>Opis</strong>
            {' '}{photo.description}
          </p>}
          {photo.technique && <p> 
            <strong>Technika</strong>
            {' '}{photo.technique}
          </p>}
          {photo.dimensions && <p> 
            <strong>Wymiary</strong>
            {' '}{photo.dimensions}
          </p>}
        </aside>
      </div>
      <button className="lightbox-btn lightbox-close" onClick={onClose}>×</button>
      <button className="lightbox-btn lightbox-prev" onClick={(e: React.MouseEvent) => { e.stopPropagation(); onNavigate(-1); }}>❮</button>
      <button className="lightbox-btn lightbox-next" onClick={(e: React.MouseEvent) => { e.stopPropagation(); onNavigate(1); }}>❯</button>
    </div>
  );
};

type ContentPageProps = {
    pageName: Exclude<PageName, 'portfolio'>;
};

const ContentPage = ({ pageName }: ContentPageProps) => {
    const [parts, setParts] = useState<string[]>([]);
    const [carouselImages, setCarouselImages] = useState<string[]>([]);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState<string | null>(null);

    useEffect(() => {
        setLoading(true);
        setError(null);
        setParts([]);
        setCarouselImages([]);

        const fetchContent = async () => {
            const cacheBuster = `?v=${new Date().getTime()}`;
            try {
                const response = await fetch(`./${pageName}.html${cacheBuster}`);
                if (!response.ok) {
                    throw new Error(`Nie można wczytać pliku ${pageName}.html`);
                }
                const html = await response.text();
                const htmlParts = html.split('<!-- CAROUSEL_PLACEHOLDER -->');
                setParts(htmlParts);

                if ((pageName === 'bio' || pageName === 'exhibitions') && htmlParts.length > 1) {
                    try {
                        const carouselResponse = await fetch(`./carousel_${pageName}.json${cacheBuster}`);
                        if (carouselResponse.ok) {
                            const images = await carouselResponse.json();
                            setCarouselImages(images);
                        } else {
                            console.warn(`Plik carousel_${pageName}.json nie został znaleziony lub jest pusty.`);
                        }
                    } catch (carouselError) {
                        console.error(`Błąd wczytywania karuzeli dla ${pageName}:`, carouselError);
                    }
                }
            } catch (err) {
                console.error(err);
                setError('Wystąpił błąd podczas ładowania treści.');
            } finally {
                setLoading(false);
            }
        };

        fetchContent();
    }, [pageName]);

    const containerClasses = ['container', 'content-page'];
    if (pageName === 'bio' || pageName === 'exhibitions') {
        containerClasses.push('content-page--full-width');
    }
    if (pageName === 'exhibitions') {
        containerClasses.push('content-page--exhibitions');
    }

    return (
        <div className={containerClasses.join(' ')}>
            {loading && <p>Ładowanie...</p>}
            {error && <p>{error}</p>}
            {!loading && !error && (
                <>
                    {parts[0] && <div dangerouslySetInnerHTML={{ __html: parts[0] }} />}
                    
                    {parts.length > 1 && <Carousel images={carouselImages} />}

                    {parts[1] && <div dangerouslySetInnerHTML={{ __html: parts[1] }} />}
                </>
            )}
        </div>
    );
};


const Footer = () => (
  <footer>
    <div className="container footer-container">
      <p>{`© ${new Date().getFullYear()} MAREK PRZYBYŁ`}</p>
      <div className="social-links">
        <a href="https://tiktok.com" target="_blank" rel="noopener noreferrer">TikTok</a>
        <a href="https://instagram.com" target="_blank" rel="noopener noreferrer">Instagram</a>
      </div>
    </div>
  </footer>
);


const App = () => {
  const [photos, setPhotos] = useState<Photo[]>([]);
  const [initialOrder, setInitialOrder] = useState<Photo[]>([]);
  const [currentPage, setCurrentPage] = useState<PageName>('portfolio');
  const [filters, setFilters] = useState<Filters>({ cycle: [], year: [], searchTerm: '' });
  const [sortOrder, setSortOrder] = useState<SortOrder>('random');
  const [selectedPhotoIndex, setSelectedPhotoIndex] = useState<number | null>(null);
  const [visibleCount, setVisibleCount] = useState(12); // Pokaż 12 zdjęć na start
  
  useEffect(() => {
    const cacheBuster = `?v=${new Date().getTime()}`;
    fetch(`./images.json${cacheBuster}`)
      .then(response => {
        if (!response.ok) {
          throw new Error("Nie można wczytać pliku images.json");
        }
        return response.json();
      })
      .then((data: Photo[]) => {
          setPhotos(data);
          setInitialOrder(shuffleArray(data));
      })
      .catch(error => console.error('Błąd wczytywania danych zdjęć:', error));
  }, []);

  const processedPhotos = useMemo(() => {
    const photosToFilter = sortOrder === 'random' ? initialOrder : photos;

    const filtered = photosToFilter.filter(photo => {
      const year = new Date(photo.date).getFullYear();
      if (filters.cycle.length > 0 && !filters.cycle.includes(photo.cycle)) return false;
      if (filters.year.length > 0 && !filters.year.includes(year)) return false;
      if (filters.searchTerm) {
          const searchTerm = filters.searchTerm.toLowerCase();
          const searchableText = `${photo.title} ${photo.cycle} ${photo.date} ${photo.description} ${photo.technique} ${photo.tags.join(' ')}`.toLowerCase();
          if (!searchableText.includes(searchTerm)) return false;
      }
      return true;
    });

    if (sortOrder === 'random') {
        return filtered;
    }

    const sorted = [...filtered].sort((a, b) => {
        switch (sortOrder) {
            case 'date-desc':
                return new Date(b.date).getTime() - new Date(a.date).getTime();
            case 'date-asc':
                return new Date(a.date).getTime() - new Date(b.date).getTime();
            case 'cycle-asc':
                return a.cycle.localeCompare(b.cycle);
            case 'cycle-desc':
                return b.cycle.localeCompare(a.cycle);
            case 'size-desc':
                return parseDimensions(b.dimensions) - parseDimensions(a.dimensions);
            case 'size-asc':
                return parseDimensions(a.dimensions) - parseDimensions(b.dimensions);
            default:
                return 0;
        }
    });

    return sorted;
  }, [filters, photos, initialOrder, sortOrder]);

  const visiblePhotos = useMemo(() => {
    return processedPhotos.slice(0, visibleCount);
  }, [processedPhotos, visibleCount]);

  useEffect(() => {
    const handleScroll = () => {
      if (window.innerHeight + document.documentElement.scrollTop >= document.documentElement.offsetHeight - 500) {
        if (visibleCount < processedPhotos.length) {
          setVisibleCount(prevCount => prevCount + 8); // Doładuj 8 kolejnych zdjęć
        }
      }
    };

    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [visibleCount, processedPhotos.length]);


  useEffect(() => {
      setVisibleCount(12); // Resetuj widoczne zdjęcia przy zmianie filtrów
  }, [filters, sortOrder]);


  const handleNavigateLightbox = (direction: number) => {
      if (selectedPhotoIndex === null) return;
      let newIndex = selectedPhotoIndex + direction;
      // Pętla nawigacji
      if (newIndex < 0) newIndex = processedPhotos.length - 1;
      if (newIndex >= processedPhotos.length) newIndex = 0;
      setSelectedPhotoIndex(newIndex);
  };

  const findOriginalIndex = (photoId: number) => {
    return processedPhotos.findIndex(p => p.id === photoId);
  }

  return (
    <React.Fragment>
      <Header currentPage={currentPage} setCurrentPage={setCurrentPage} />
      <main>
        {currentPage === 'portfolio' ? (
          <div className="container gallery-layout">
            <FilterPanel 
              photos={photos} 
              activeFilters={filters} 
              setFilters={setFilters}
              sortOrder={sortOrder}
              setSortOrder={setSortOrder}
            />
            <div className="gallery-main-content">
                <PhotoGrid 
                  photos={visiblePhotos} 
                  onPhotoClick={(index) => {
                      const photoId = visiblePhotos[index].id;
                      setSelectedPhotoIndex(findOriginalIndex(photoId));
                  }} 
                />
            </div>
          </div>
        ) : (
          <ContentPage pageName={currentPage} />
        )}
      </main>
      <Footer />
      <Lightbox 
        photos={processedPhotos} 
        activeIndex={selectedPhotoIndex} 
        onClose={() => setSelectedPhotoIndex(null)}
        onNavigate={handleNavigateLightbox}
      />
    </React.Fragment>
  );
};

const container = document.getElementById('root');
if (container) {
    const root = createRoot(container);
    root.render(<App />);
} else {
    console.error('Błąd krytyczny: Nie znaleziono elementu #root w dokumencie. Aplikacja nie może zostać uruchomiona.');
}