'use client';
import { Suspense, useCallback, useMemo, useState } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import { useLocale, useTranslations } from 'next-intl';
import { Box, Chip, Stack, Typography } from '@mui/material';
import type { SxProps, Theme } from '@mui/material';
import { AppButton, AppLoading, EmptyState, ErrorState, NurseResultCard } from '@/components';
import { ROUTES } from '@/constants';
import { useServiceCategories } from '@/services/catalog';
import { pickCatalogName } from '@/services/catalog/names';
import { useCities, useDistricts } from '@/services/geography';
import { pickRegionName } from '@/services/geography/names';
import { useNurseSearch } from '@/services/search';
import { searchParamsToFilters } from '@/services/search/filterParams';
import { SEARCH_PAGE_SIZE } from '@/services/search/constants';
import { formatIrrToToman } from '@/utils';
import type { NurseSearchResult } from '@/services/search/types';

/** Single column on mobile; two columns above `md` (~900px) so the extra desktop width goes toward
 * wider cards instead of one long phone-column list (§3.10 — a full list+detail split is DEFERRED). */
const RESULTS_GRID_SX: SxProps<Theme> = {
  display: 'grid',
  gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' },
  gap: 1.5,
  alignItems: 'start',
};

/**
 * C2 — Results (نتایج جستجو): the rating-sorted list of **only verified, accepting** nurses for the
 * carried filter set. The filter set lives in the URL (the deep-linkable, back/forward-safe cache key),
 * so returning to a prior filter URL is a cache hit with zero network calls (`useNurseSearch` +
 * `keepPreviousData`). A tappable **filter-recap chip row** (category · region · gender · price) deep-
 * links back to C1 carrying the *entire* current query string — every filter C1 set, including the
 * client-only `province_id`/`date` params — so C1 hydrates fully instead of resetting to just the
 * category. Renders all four states (loading skeletons / empty "relax filters" / error-retry /
 * populated). Tapping a card opens C3, carrying the nurse + variant + gender intent.
 */
export default function SearchResultsPage() {
  return (
    <Suspense fallback={<AppLoading />}>
      <ResultsScreen />
    </Suspense>
  );
}

function ResultsScreen() {
  const t = useTranslations('search');
  const tc = useTranslations('common');
  const locale = useLocale();
  const router = useRouter();
  const params = useSearchParams();

  const [pageSize, setPageSize] = useState(SEARCH_PAGE_SIZE);

  // The URL is the source of truth for the filter set; grow only the page size for "load more".
  const filters = useMemo(() => ({ ...searchParamsToFilters(params), pageSize }), [params, pageSize]);
  const dateIntent = params.get('date') ?? undefined;
  const provinceIdParam = params.get('province_id');

  const { data, isLoading, isError, isFetching, refetch } = useNurseSearch(filters);
  const items = data?.items ?? [];
  const total = data?.total ?? 0;
  const hasMore = items.length < total;

  const { data: categoriesData } = useServiceCategories();
  const categories = useMemo(() => categoriesData?.items ?? [], [categoriesData]);
  const categoryLabelById = useMemo(() => {
    const map = new Map<number, string>();
    categories.forEach((category) => map.set(category.id, pickCatalogName(category, locale)));
    return map;
  }, [categories, locale]);
  const categoryLabel = categoryLabelById.get(filters.serviceCategoryId);

  const { data: cities } = useCities(provinceIdParam ? Number(provinceIdParam) : undefined);
  const { data: districts } = useDistricts(filters.cityId || undefined);
  const city = cities?.find((candidate) => candidate.id === filters.cityId);
  const district = filters.districtId ? districts?.find((candidate) => candidate.id === filters.districtId) : undefined;
  const regionLabel = city
    ? `${pickRegionName(city, locale)} · ${district ? pickRegionName(district, locale) : t('whole_city')}`
    : undefined;

  const genderLabel = t(`gender_${filters.nurseGender ?? 'any'}`);

  const priceLabel = filters.priceMin
    ? filters.priceMax
      ? t('price_chip_range', {
          min: formatIrrToToman(filters.priceMin, locale),
          max: formatIrrToToman(filters.priceMax, locale),
        })
      : t('price_chip_min', { min: formatIrrToToman(filters.priceMin, locale) })
    : filters.priceMax
      ? t('price_chip_max', { max: formatIrrToToman(filters.priceMax, locale) })
      : undefined;

  const backToFilters = useCallback(
    () => router.push(`/${locale}${ROUTES.SEARCH}?${params.toString()}`),
    [router, locale, params],
  );

  const openProfile = useCallback(
    (nurse: NurseSearchResult) => {
      const query = new URLSearchParams();
      query.set('variant_id', String(nurse.variantId));
      query.set('service_category_id', String(filters.serviceCategoryId));
      query.set('city_id', String(filters.cityId));
      if (filters.nurseGender) query.set('required_gender', filters.nurseGender);
      if (dateIntent) query.set('date', dateIntent);
      router.push(`/${locale}${ROUTES.SEARCH_NURSE}/${nurse.nurseId}?${query.toString()}`);
    },
    [router, locale, filters.serviceCategoryId, filters.cityId, filters.nurseGender, dateIntent],
  );

  return (
    <Stack sx={{ gap: 2 }}>
      <Stack sx={{ gap: 0.25 }}>
        <Typography variant="h6" component="h1">
          {isLoading ? t('results_loading_title') : t('results_count', { count: total })}
        </Typography>
        {/* Rating is the only MVP sort — a static caption, not a dead-interactive dropdown. Other
            sorts are DEFERRED until the API grows them. */}
        <Typography variant="body2" sx={{ color: 'text.secondary' }}>
          {t('sort_static')}
        </Typography>
      </Stack>

      <Stack direction="row" sx={{ gap: 1, flexWrap: 'wrap' }}>
        {categoryLabel ? (
          <Chip label={categoryLabel} onClick={backToFilters} data-recap-chip="category" />
        ) : null}
        {regionLabel ? <Chip label={regionLabel} onClick={backToFilters} data-recap-chip="region" /> : null}
        <Chip label={genderLabel} onClick={backToFilters} data-recap-chip="gender" />
        {priceLabel ? <Chip label={priceLabel} onClick={backToFilters} data-recap-chip="price" /> : null}
      </Stack>

      {isLoading ? (
        <Box sx={RESULTS_GRID_SX}>
          {[0, 1, 2, 3].map((key) => (
            <NurseResultCard.Skeleton key={key} />
          ))}
        </Box>
      ) : isError ? (
        <ErrorState message={t('results_error')} retryLabel={tc('retry')} onRetry={() => refetch()} />
      ) : items.length === 0 ? (
        <RelaxFiltersEmptyState onRelax={backToFilters} />
      ) : (
        // Above ~900px (`md`), a two-column grid uses the extra width instead of one long phone-column
        // (the doc's "wider cards" option — a full list+detail split is DEFERRED, see the phase doc).
        <Box sx={RESULTS_GRID_SX}>
          {items.map((nurse) => (
            <NurseResultCard
              key={`${nurse.nurseId}-${nurse.variantId}`}
              nurse={nurse}
              serviceLabel={categoryLabelById.get(nurse.serviceCategoryId) ?? t('unnamed_service')}
              onSelect={openProfile}
            />
          ))}
          {hasMore ? (
            <AppButton
              variant="outlined"
              color="primary"
              onClick={() => setPageSize((size) => size + SEARCH_PAGE_SIZE)}
              disabled={isFetching}
              sx={{ alignSelf: 'center', gridColumn: '1 / -1' }}
            >
              {t('load_more')}
            </AppButton>
          ) : null}
        </Box>
      )}
    </Stack>
  );
}

/** The "no nurses match → relax your filters" state with concrete, product-aligned suggestions. */
function RelaxFiltersEmptyState({ onRelax }: { onRelax: () => void }) {
  const t = useTranslations('search');
  return (
    <EmptyState
      icon="search"
      title={t('empty_title')}
      body={
        <Stack sx={{ gap: 0.5 }}>
          <Typography variant="body2" sx={{ color: 'text.secondary' }}>
            {t('empty_suggest_gender')}
          </Typography>
          <Typography variant="body2" sx={{ color: 'text.secondary' }}>
            {t('empty_suggest_district')}
          </Typography>
          <Typography variant="body2" sx={{ color: 'text.secondary' }}>
            {t('empty_suggest_date')}
          </Typography>
        </Stack>
      }
      action={
        <AppButton variant="contained" color="primary" onClick={onRelax} startIcon="tune">
          {t('empty_cta')}
        </AppButton>
      }
    />
  );
}
