'use client';

import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { DashboardLayout } from '@/components/layout/DashboardLayout';
import {
  applyWorkerJobFeedFilters,
  countActiveWorkerJobFeedFilters,
  defaultWorkerJobFeedFilters,
  FeedJob,
  JobFeedCard,
  JobFeedEmpty,
  JobFeedList,
  JobFeedSkeleton,
  type WorkerJobFeedFilters,
} from '@/components/jobs/JobFeed';
import {
  WorkerJobFeedFilterButton,
  WorkerJobFeedFilterModal,
} from '@/components/jobs/WorkerJobFeedFilterModal';
import { JobsMapPanel } from '@/components/jobs/JobsMapPanel';
import { useInfiniteScroll } from '@/hooks/useInfiniteScroll';
import { api } from '@/lib/api';
import {
  applyJobReactionUpdate,
  applyOptimisticJobReaction,
} from '@/lib/jobReactions';
import { appendAreaQuery, isRegionFilterActive, regionLabel } from '@/lib/region';
import { cn } from '@/lib/utils';
import { useAuth } from '@/contexts/AuthContext';
import { useSocket, SOCKET_EVENTS } from '@/contexts/SocketContext';
import type { JobReactionType, JobReactionUpdatePayload } from '@ehandyhire/shared';
import { Briefcase, Columns2, LayoutList, Map } from 'lucide-react';

type JobsViewMode = 'feed' | 'map' | 'split';
type CategoryOption = { id: string; name: string; slug: string; icon?: string };

const PAGE_SIZE = 15;

interface PaginationMeta {
  page: number;
  limit: number;
  total: number;
  totalPages: number;
}

function buildWorkerJobsQuery(filters: WorkerJobFeedFilters, page: number) {
  const params = new URLSearchParams({
    page: String(page),
    limit: String(PAGE_SIZE),
    status: filters.status === 'all' ? 'OPEN,QUOTED' : filters.status,
  });
  if (filters.categorySlug) params.set('categorySlug', filters.categorySlug);
  appendAreaQuery(params, filters.regionSlug);
  return params.toString();
}

function mergeFeedJobs(prev: FeedJob[], next: FeedJob[]) {
  if (next.length === 0) return prev;
  const ids = new Set(prev.map((job) => job.id));
  const unique = next.filter((job) => !ids.has(job.id));
  return unique.length > 0 ? [...prev, ...unique] : prev;
}

function getEmptyMessage(filters: WorkerJobFeedFilters) {
  if (filters.feed === 'new') {
    return {
      title: 'No new posts',
      body: 'Jobs posted in the last few days will show up when you filter by New.',
    };
  }
  if (countActiveWorkerJobFeedFilters(filters) > 0) {
    return {
      title: 'No jobs match your filters',
      body: isRegionFilterActive(filters.regionSlug)
        ? `No jobs found in ${regionLabel(filters.regionSlug)} with the current filters. Try a wider region or reset.`
        : 'Try adjusting your filters or reset to see all available jobs.',
    };
  }
  return {
    title: 'No jobs in your feed yet',
    body: 'New customer posts will show up here. Check back soon or update your skills and service areas.',
  };
}

export default function WorkerJobsPage() {
  const { user } = useAuth();
  const { socket, isConnected } = useSocket();
  const [jobs, setJobs] = useState<FeedJob[]>([]);
  const [categories, setCategories] = useState<CategoryOption[]>([]);
  const [loading, setLoading] = useState(true);
  const [loadingMore, setLoadingMore] = useState(false);
  const [hasMore, setHasMore] = useState(true);
  const [page, setPage] = useState(1);
  const [filters, setFilters] = useState<WorkerJobFeedFilters>(defaultWorkerJobFeedFilters);
  const [filterOpen, setFilterOpen] = useState(false);
  const [viewMode, setViewMode] = useState<JobsViewMode>('feed');
  const fetchIdRef = useRef(0);

  const serverFilterKey = useMemo(
    () => `${filters.status}|${filters.categorySlug}|${filters.regionSlug}`,
    [filters.status, filters.categorySlug, filters.regionSlug]
  );

  const fetchJobsPage = useCallback(
    async (pageNum: number, replace: boolean, activeFilters: WorkerJobFeedFilters) => {
      const fetchId = ++fetchIdRef.current;
      if (pageNum === 1) setLoading(true);
      else setLoadingMore(true);

      try {
        const res = await api<{ data: FeedJob[]; meta: PaginationMeta }>(
          `/jobs?${buildWorkerJobsQuery(activeFilters, pageNum)}`
        );
        if (fetchId !== fetchIdRef.current) return;

        setJobs((prev) => (replace ? res.data : mergeFeedJobs(prev, res.data)));
        setPage(pageNum);
        setHasMore(res.meta.page < res.meta.totalPages);
      } catch (error) {
        if (fetchId === fetchIdRef.current) console.error(error);
      } finally {
        if (fetchId === fetchIdRef.current) {
          setLoading(false);
          setLoadingMore(false);
        }
      }
    },
    []
  );

  useEffect(() => {
    setJobs([]);
    setPage(1);
    setHasMore(true);
    fetchJobsPage(1, true, filters);
  }, [serverFilterKey, fetchJobsPage]);

  useEffect(() => {
    api<{ data: CategoryOption[] }>('/categories?limit=50')
      .then((res) => setCategories(res.data))
      .catch(console.error);
  }, []);

  const loadMore = useCallback(() => {
    if (loading || loadingMore || !hasMore) return;
    fetchJobsPage(page + 1, false, filters);
  }, [loading, loadingMore, hasMore, page, filters, fetchJobsPage]);

  useEffect(() => {
    if (!socket || !isConnected) return;

    socket.emit(SOCKET_EVENTS.JOIN_JOB_FEED);

    const onReaction = (payload: JobReactionUpdatePayload) => {
      setJobs((prev) =>
        prev.map((job) =>
          job.id === payload.jobId
            ? applyJobReactionUpdate(job, payload, user?.id)
            : job
        )
      );
    };

    socket.on(SOCKET_EVENTS.JOB_REACTION, onReaction);

    return () => {
      socket.emit(SOCKET_EVENTS.LEAVE_JOB_FEED);
      socket.off(SOCKET_EVENTS.JOB_REACTION, onReaction);
    };
  }, [socket, isConnected, user?.id]);

  const handleReact = useCallback(
    (jobId: string, type: JobReactionType) => {
      if (!socket || !isConnected || !user) return;

      setJobs((prev) =>
        prev.map((job) => (job.id === jobId ? applyOptimisticJobReaction(job, type) : job))
      );
      socket.emit(SOCKET_EVENTS.SET_JOB_REACTION, { jobId, type });
    },
    [socket, isConnected, user]
  );

  const filteredJobs = useMemo(
    () => applyWorkerJobFeedFilters(jobs, filters),
    [jobs, filters]
  );

  const activeFilterCount = useMemo(() => countActiveWorkerJobFeedFilters(filters), [filters]);
  const emptyMessage = useMemo(() => getEmptyMessage(filters), [filters]);

  const showFeed = viewMode === 'feed' || viewMode === 'split';
  const showMap = viewMode === 'map' || viewMode === 'split';

  const sentinelRef = useInfiniteScroll(loadMore, {
    enabled: hasMore && !loading && !loadingMore && jobs.length > 0,
  });

  return (
    <DashboardLayout role="worker" title="Available jobs">
      <div
        className={cn(
          'space-y-4',
          viewMode === 'feed' ? 'mx-auto max-w-2xl' : 'max-w-6xl'
        )}
      >
        <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
          <div className="min-w-0 flex-1">
            <p className="text-sm leading-relaxed text-muted">
              {viewMode === 'map'
                ? 'Green pins are open jobs — tap one for details or to send a quote.'
                : 'Latest jobs from customers — scroll your feed or switch to map to see what’s nearby.'}
            </p>
            {!loading && (
              <p className="mt-1 text-xs text-muted">
                <Briefcase className="mr-1 inline h-3.5 w-3.5 -mt-0.5 text-primary" />
                <span className="font-semibold text-slate-700">
                  {filteredJobs.length}
                  {hasMore ? '+' : ''}
                </span>{' '}
                job
                {filteredJobs.length !== 1 || hasMore ? 's' : ''}
                {isRegionFilterActive(filters.regionSlug)
                  ? ` in ${regionLabel(filters.regionSlug)}`
                  : null}
                {activeFilterCount > 0 ? ' matching filters' : ''}
              </p>
            )}
          </div>

          <div className="flex shrink-0 items-center gap-2">
            <WorkerJobFeedFilterButton
              activeCount={activeFilterCount}
              onClick={() => setFilterOpen(true)}
            />
            {([
              { value: 'feed' as const, label: 'Feed', icon: LayoutList },
              { value: 'map' as const, label: 'Map', icon: Map },
              { value: 'split' as const, label: 'Split', icon: Columns2, desktopOnly: true },
            ]).map((item) => (
              <button
                key={item.value}
                type="button"
                onClick={() => setViewMode(item.value)}
                className={cn(
                  'filter-chip gap-1.5',
                  viewMode === item.value && 'filter-chip-active',
                  item.desktopOnly && 'hidden lg:inline-flex'
                )}
              >
                <item.icon className="h-3.5 w-3.5" />
                <span className="hidden sm:inline">{item.label}</span>
              </button>
            ))}
          </div>
        </div>

        <div
          className={cn(
            showFeed && showMap && 'lg:grid lg:grid-cols-[minmax(0,1fr)_min(400px,38%)] lg:gap-6 lg:items-start'
          )}
        >
          {showFeed && (
            <div className={cn(viewMode === 'split' && 'min-w-0')}>
              {loading ? (
                <JobFeedSkeleton count={viewMode === 'split' ? 2 : 3} />
              ) : filteredJobs.length === 0 ? (
                <JobFeedEmpty title={emptyMessage.title} body={emptyMessage.body} />
              ) : (
                <JobFeedList>
                  {filteredJobs.map((job) => (
                    <JobFeedCard
                      key={job.id}
                      job={job}
                      href={`/worker/jobs/${job.id}`}
                      mode="discovery"
                      onReact={handleReact}
                      reactionsDisabled={!isConnected}
                    />
                  ))}
                </JobFeedList>
              )}
            </div>
          )}

          {showMap && (
            <JobsMapPanel
              jobs={filteredJobs as unknown as Record<string, unknown>[]}
              loading={loading}
              jobHref={(id) => `/worker/jobs/${id}`}
              emptyTitle={emptyMessage.title}
              emptySubtitle={emptyMessage.body}
              className={cn(
                viewMode === 'split'
                  ? 'mt-2 h-[min(70vh,560px)] lg:mt-0 lg:sticky lg:top-20 lg:h-[calc(100vh-6rem)]'
                  : 'h-[min(72vh,640px)] min-h-[420px]'
              )}
            />
          )}
        </div>

        {!loading && jobs.length > 0 && (
          <div ref={sentinelRef} className="py-2" aria-hidden>
            {loadingMore && showFeed && (
              <div className="pt-2">
                <JobFeedSkeleton count={viewMode === 'split' ? 1 : 2} />
              </div>
            )}
            {loadingMore && !showFeed && (
              <p className="text-center text-sm text-muted">Loading more jobs…</p>
            )}
          </div>
        )}
      </div>

      <WorkerJobFeedFilterModal
        open={filterOpen}
        onClose={() => setFilterOpen(false)}
        filters={filters}
        onChange={setFilters}
        categories={categories}
        resultCount={filteredJobs.length}
      />
    </DashboardLayout>
  );
}
