import type { User } from 'oidc-client-ts';
import { useEffect, useState, useRef, useCallback } from 'react';
import './App.css';
import { getUser } from './auth/authService';
import AlertError from './components/AlertError';
import LoginModal from './components/LoginModal';
import AuthCallback from './components/AuthCallback';
import { Map } from './components/Map';
import { FilterPanel, type ParameterValues, DEFAULT_FILTER_VALUES } from './components/FilterPanel';
import { Header } from './components/Header';
import { StatsBar, type ViewMode } from './components/StatsBar';
import { ListView } from './components/ListView';
import { StreamingProgressBar } from './components/StreamingProgressBar';
import { Sheet, SheetContent, SheetTrigger } from './components/ui/sheet';
import { Button } from './components/ui/button';
import { Filter } from 'lucide-react';
import type { GeoJSONFeatureCollection, PropertyProperties, PropertyFeature } from '@/types';
import { refreshListings, fetchTasksForUser, streamListingGeoJSON, type StreamingProgress } from '@/services';

function App() {
  const [listingData, setListingData] = useState<GeoJSONFeatureCollection | null>(null);
  const [taskID, setTaskID] = useState<string | null>(null);
  const [user, setUser] = useState<User | null>(null);
  const [queryParameters, setQueryParameters] = useState<ParameterValues | null>(null);
  const [submitError, setSubmitError] = useState<string | null>(null);
  const [alertDialogIsOpen, setAlertDialogIsOpen] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [viewMode, setViewMode] = useState<ViewMode>('map');
  const [mobileFilterOpen, setMobileFilterOpen] = useState(false);
  const [highlightedProperty, setHighlightedProperty] = useState<string | null>(null);
  const [streamingProgress, setStreamingProgress] = useState<StreamingProgress | null>(null);

  // Ref to track accumulated features during streaming
  const accumulatedFeaturesRef = useRef<PropertyFeature[]>([]);
  // Ref to track if initial load has been triggered
  const initialLoadTriggeredRef = useRef(false);

  // Check if this is the callback route - render dedicated component
  if (window.location.pathname === '/callback') {
    return <AuthCallback />;
  }

  useEffect(() => {
    // Load user data
    getUser().then(setUser);
  }, []);

  useEffect(() => {
    if (!user) {
      return;
    }
    fetchTasksForUser(user).then((tasks) => {
      if (tasks && tasks.length > 0) {
        setTaskID(tasks[0]);
      }
    });
  }, [user, taskID]);

  // Load listings function - used by both auto-load and manual submit
  const loadListings = useCallback(async (parameters: ParameterValues) => {
    if (!user) return;

    setQueryParameters(parameters);
    setMobileFilterOpen(false);
    setIsLoading(true);
    accumulatedFeaturesRef.current = [];
    setStreamingProgress({ count: 0 });
    setListingData(null);

    let updateScheduled = false;

    const flushUpdate = () => {
      updateScheduled = false;
      setListingData({
        type: 'FeatureCollection',
        features: [...accumulatedFeaturesRef.current]
      });
    };

    const scheduleUpdate = () => {
      if (!updateScheduled) {
        updateScheduled = true;
        requestAnimationFrame(flushUpdate);
      }
    };

    try {
      for await (const batch of streamListingGeoJSON(user, parameters, (progress) => {
        setStreamingProgress(progress);
      })) {
        accumulatedFeaturesRef.current.push(...batch);
        scheduleUpdate();
      }
      // Final flush to ensure all data is rendered
      flushUpdate();
    } catch (error) {
      if (error instanceof Error) {
        setSubmitError(error.message);
      } else {
        setSubmitError(String(error));
      }
      setAlertDialogIsOpen(true);
    } finally {
      setIsLoading(false);
      setStreamingProgress(null);
    }
  }, [user]);

  // Auto-load data with default filters when user is authenticated
  useEffect(() => {
    if (!user || initialLoadTriggeredRef.current) {
      return;
    }
    initialLoadTriggeredRef.current = true;

    const defaultParams: ParameterValues = {
      ...DEFAULT_FILTER_VALUES,
      available_from: new Date(),
    };

    loadListings(defaultParams);
  }, [user, loadListings]);

  if (!user) {
    return <LoginModal isOpen={user === null} />;
  }

  const onSubmit = async (action: 'fetch-data' | 'visualize', parameters: ParameterValues) => {
    if (action === 'visualize') {
      loadListings(parameters);
    } else if (action === 'fetch-data') {
      setQueryParameters(parameters);
      setMobileFilterOpen(false);
      setIsLoading(true);
      try {
        const data = await refreshListings(user!, parameters);
        setTaskID(data.task_id);
      } catch (error) {
        if (error instanceof Error) {
          setSubmitError(error.message);
        } else {
          setSubmitError(String(error));
        }
        setAlertDialogIsOpen(true);
      } finally {
        setIsLoading(false);
      }
    }
  };

  const handlePropertyClick = (property: PropertyProperties, _coordinates: [number, number]) => {
    setHighlightedProperty(property.url);
    // Optionally: pan map to coordinates
  };

  const renderMainContent = () => {
    if (!listingData) {
      return (
        <div className="flex-1 flex items-center justify-center bg-muted/20">
          <div className="text-center p-8 max-w-md">
            {isLoading ? (
              <>
                <div className="text-6xl mb-4 animate-pulse">🏠</div>
                <h2 className="text-xl font-semibold mb-2">Loading Properties...</h2>
                <p className="text-muted-foreground mb-4">
                  Fetching listings with default filters. You can adjust filters on the left.
                </p>
              </>
            ) : (
              <>
                <div className="text-6xl mb-4">🏠</div>
                <h2 className="text-xl font-semibold mb-2">Welcome to Property Explorer</h2>
                <p className="text-muted-foreground mb-4">
                  Use the filters on the left to find properties. Apply filters to visualize existing data or refresh to fetch new listings.
                </p>
              </>
            )}
          </div>
        </div>
      );
    }

    if (listingData.features.length === 0) {
      return (
        <div className="flex-1 flex items-center justify-center">
          <div className="text-center p-8">
            <div className="text-6xl mb-4">🔍</div>
            <h2 className="text-xl font-semibold mb-2">No listings found</h2>
            <p className="text-muted-foreground">
              Try adjusting the filters or run a data refresh to fetch new listings.
            </p>
          </div>
        </div>
      );
    }

    return (
      <>
        {/* Map View */}
        {(viewMode === 'map' || viewMode === 'split') && (
          <div className={`relative ${viewMode === 'split' ? 'w-1/2' : 'flex-1'}`} style={{ minHeight: 0 }}>
            <Map
              listingData={listingData}
              queryParameters={queryParameters}
              onPropertyClick={handlePropertyClick}
            />
          </div>
        )}

        {/* List View */}
        {(viewMode === 'list' || viewMode === 'split') && (
          <div className={`${viewMode === 'split' ? 'w-1/2 border-l' : 'flex-1'}`}>
            <ListView
              listingData={listingData}
              onPropertyClick={handlePropertyClick}
              highlightedPropertyUrl={highlightedProperty}
            />
          </div>
        )}
      </>
    );
  };

  const handleTaskCancelled = () => {
    setTaskID(null);
  };

  return (
    <div className="h-screen flex flex-col overflow-hidden">
      {/* Header */}
      <Header
        user={user}
        taskID={taskID}
        onTaskCancelled={handleTaskCancelled}
      />

      {/* Main content area */}
      <div className="flex-1 flex overflow-hidden min-h-0">
        {/* Filter Panel - Desktop (fixed sidebar) */}
        <div className="hidden md:block w-64 shrink-0 h-full overflow-hidden">
          <FilterPanel
            onSubmit={onSubmit}
            isLoading={isLoading}
            listingCount={listingData?.features.length}
          />
        </div>

        {/* Filter Panel - Mobile (sheet) */}
        <div className="md:hidden fixed bottom-4 right-4 z-50">
          <Sheet open={mobileFilterOpen} onOpenChange={setMobileFilterOpen}>
            <SheetTrigger asChild>
              <Button size="lg" className="rounded-full shadow-lg h-14 w-14">
                <Filter className="h-6 w-6" />
              </Button>
            </SheetTrigger>
            <SheetContent side="left" className="w-80 p-0">
              <FilterPanel
                onSubmit={onSubmit}
                isLoading={isLoading}
                listingCount={listingData?.features.length}
              />
            </SheetContent>
          </Sheet>
        </div>

        {/* Main View Area */}
        <div className="flex-1 flex flex-col overflow-hidden min-h-0">
          {/* Streaming Progress Bar */}
          <div className="relative shrink-0">
            <StreamingProgressBar progress={streamingProgress} isLoading={isLoading} />
          </div>

          {/* Map/List Container */}
          <div className="flex-1 flex overflow-hidden min-h-0">
            {renderMainContent()}
          </div>

          {/* Stats Bar */}
          {listingData && listingData.features.length > 0 && (
            <div className="shrink-0">
              <StatsBar
                listingData={listingData}
                viewMode={viewMode}
                onViewModeChange={setViewMode}
              />
            </div>
          )}
        </div>
      </div>

      {/* Error Dialog */}
      <AlertError message={submitError} open={alertDialogIsOpen} setIsOpen={setAlertDialogIsOpen} />
    </div>
  );
}

export default App;
