'use client';
import { Suspense, useMemo, useState } from 'react';
import { useLocale, useTranslations } from 'next-intl';
import { useRouter, useSearchParams } from 'next/navigation';
import { FormProvider, useForm, useWatch } from 'react-hook-form';
import {
  Avatar,
  Box,
  Chip,
  MenuItem,
  Skeleton,
  Stack,
  TextField,
  ToggleButton,
  ToggleButtonGroup,
  Typography,
} from '@mui/material';
import {
  AppButton,
  AppIcon,
  AppLoading,
  EmptyState,
  JalaliDateIntentPicker,
  PriceDisplay,
  RhfControlGroup,
  RhfTextField,
  StepperHeader,
  TrustBadge,
} from '@/components';
import { todayIso } from '@/components/common/JalaliDatePicker';
import { ROUTES } from '@/constants';
import { ApiError } from '@/lib/api/errors';
import { usePatients } from '@/services/patients';
import { useAddresses } from '@/services/addresses';
import { useNurseProfile } from '@/services/search';
import type { NurseProfile } from '@/services/search/types';
import { useCreateBookingRequest } from '@/services/bookingRequests';
import { CUSTOMER_NOTES_MAX_LENGTH } from '@/services/bookingRequests/constants';
import { formatNumber } from '@/utils';
import type {
  BookingRequestDisplayContext,
  RequiredCaregiverGender,
} from '@/services/bookingRequests/types';
import type { CustomerAddress } from '@/services/addresses/types';
import type { Patient } from '@/services/patients/types';

const GENDER_OPTIONS: RequiredCaregiverGender[] = ['female', 'male', 'any'];

interface TimeWindowOption {
  key: 'morning' | 'afternoon' | 'evening';
  start: string;
  end: string;
}

const TIME_WINDOWS: TimeWindowOption[] = [
  { key: 'morning', start: '08:00', end: '12:00' },
  { key: 'afternoon', start: '12:00', end: '16:00' },
  { key: 'evening', start: '16:00', end: '20:00' },
];

interface RequestFormValues {
  patientId: number | '';
  variantId: number | '';
  addressId: number | '';
  gender: RequiredCaregiverGender | '';
  date: string;
  window: TimeWindowOption['key'] | 'custom' | null;
  timeStart: string;
  timeEnd: string;
  notes: string;
}

/**
 * C4 — Booking-request form (فرم درخواست). The destination of the C3 "درخواست رزرو" CTA (it carries the
 * `nurse_id`, an optional `variant_id`, and the same-gender `required_gender` intent from search). The
 * family picks a patient (f2), one of the nurse's service variants (f4/search profile), a saved address
 * (f3), a future date + time window, the **first-class caregiver-gender** preference, and stage-1 notes,
 * then sends the request → lands on C5. Money-free: no price breakdown, no booking row (that's f9/b9).
 * `useSearchParams` requires a Suspense boundary.
 */
export default function BookingRequestFormPage() {
  return (
    <Suspense fallback={<AppLoading />}>
      <BookingRequestForm />
    </Suspense>
  );
}

/**
 * Resolves the URL hand-off and waits for every list the form defaults off before mounting it.
 *
 * The wait is load-bearing rather than cosmetic: the variant and address fields default to "the one
 * carried in the URL, else the nurse's first service / the primary address", and those defaults can
 * only be computed once the lists exist. Previously the form mounted immediately and re-derived the
 * effective value on every render (`variantSel !== '' ? variantSel : firstVariantId`), which meant the
 * *stored* value and the *shown* value could disagree, and neither field could carry a plain required
 * rule. Mounting once with real `defaultValues` makes the stored value the only value.
 */
function BookingRequestForm() {
  const t = useTranslations('booking');
  const locale = useLocale();
  const router = useRouter();
  const query = useSearchParams();

  const nurseId = Number(query.get('nurse_id'));
  const hasNurse = Number.isInteger(nurseId) && nurseId > 0;
  const variantIdParam = Number(query.get('variant_id')) || null;
  const genderParam = query.get('required_gender');
  // Recovery hand-off from C5's "request again with another time" — reopens this same nurse/variant
  // prefilled with the patient + address of the terminal request, extending the C3 handoff params.
  const patientIdParam = Number(query.get('patient_id')) || null;
  const addressIdParam = Number(query.get('address_id')) || null;

  const profileQuery = useNurseProfile(hasNurse ? nurseId : undefined);
  const patientsQuery = usePatients();
  const addressesQuery = useAddresses();

  if (!hasNurse) {
    return (
      <EmptyState
        icon="search"
        title={t('missing_nurse_title')}
        body={t('missing_nurse_body')}
        action={
          <AppButton
            variant="contained"
            color="primary"
            onClick={() => router.push(`/${locale}${ROUTES.SEARCH}`)}
            sx={{ m: 0 }}
          >
            {t('missing_nurse_cta')}
          </AppButton>
        }
      />
    );
  }

  if (profileQuery.isLoading || patientsQuery.isLoading || addressesQuery.isLoading) return <FormSkeleton />;

  return (
    <RequestForm
      nurseId={nurseId}
      profile={profileQuery.data}
      patients={patientsQuery.data?.items ?? []}
      addresses={addressesQuery.data?.items ?? []}
      carried={{
        variantId: variantIdParam,
        patientId: patientIdParam,
        addressId: addressIdParam,
        gender: genderParam === 'male' || genderParam === 'female' ? genderParam : null,
      }}
    />
  );
}

function RequestForm({
  nurseId,
  profile,
  patients,
  addresses,
  carried,
}: {
  nurseId: number;
  profile: NurseProfile | undefined;
  patients: Patient[];
  addresses: CustomerAddress[];
  carried: {
    variantId: number | null;
    patientId: number | null;
    addressId: number | null;
    gender: RequiredCaregiverGender | null;
  };
}) {
  const t = useTranslations('booking');
  const locale = useLocale();
  const router = useRouter();
  const createRequest = useCreateBookingRequest();

  const services = useMemo(() => profile?.services ?? [], [profile]);
  const [addressEditing, setAddressEditing] = useState(false);
  const [formError, setFormError] = useState<string | null>(null);

  const primaryAddressId: number | '' =
    addresses.length > 0 ? (addresses.find((address) => address.isPrimary)?.id ?? addresses[0].id) : '';

  const form = useForm<RequestFormValues>({
    mode: 'onTouched',
    defaultValues: {
      patientId: carried.patientId ?? '',
      variantId: carried.variantId ?? (services.length > 0 ? services[0].variantId : ''),
      addressId: carried.addressId ?? primaryAddressId,
      gender: carried.gender ?? '',
      date: '',
      window: null,
      timeStart: '',
      timeEnd: '',
      notes: '',
    },
  });
  const { control, handleSubmit, setValue, getValues } = form;
  const values = useWatch({ control });

  const patientId = values.patientId ?? '';
  const variantId = values.variantId ?? '';
  const addressId = values.addressId ?? '';
  const gender = values.gender ?? '';
  const notes = values.notes ?? '';
  const windowSel = values.window ?? null;

  const selectedVariant = services.find((service) => service.variantId === variantId);
  const selectedAddress = addresses.find((address) => address.id === addressId);
  const selectedPatient = patients.find((patient) => patient.id === patientId);

  // A concrete gender that contradicts the (single) nurse's gender is a same-gender mismatch (400) —
  // block it inline before the round-trip; the server re-validates and is authoritative.
  const genderMismatch = gender !== '' && gender !== 'any' && profile != null && gender !== profile.nurseGender;

  const missingFieldLabels: string[] = [];
  if (patientId === '') missingFieldLabels.push(t('cta_missing_patient'));
  if (variantId === '') missingFieldLabels.push(t('cta_missing_service'));
  if (addressId === '') missingFieldLabels.push(t('cta_missing_address'));
  if (values.date === '') missingFieldLabels.push(t('cta_missing_date'));
  if (values.timeStart === '' || values.timeEnd === '') missingFieldLabels.push(t('cta_missing_time'));
  if (gender === '') missingFieldLabels.push(t('cta_missing_gender'));
  const requiredChosen = missingFieldLabels.length === 0;

  const regionLabel = (address: CustomerAddress): string => {
    const city = locale === 'en' ? address.cityNameEn : address.cityNameFa;
    const district =
      address.districtId == null
        ? t('address_whole_city')
        : locale === 'en'
          ? address.districtNameEn
          : address.districtNameFa;
    return `${address.title} · ${city} · ${district}`;
  };

  const selectWindow = (option: TimeWindowOption) => {
    setValue('window', option.key, { shouldDirty: true });
    setValue('timeStart', option.start, { shouldValidate: true });
    setValue('timeEnd', option.end, { shouldValidate: true });
    // The date's past-guard is a cross-field rule over the start time — re-run it now that one exists.
    if (getValues('date')) void form.trigger('date');
  };

  const submit = (formValues: RequestFormValues) => {
    setFormError(null);
    if (genderMismatch) return;

    const context: BookingRequestDisplayContext | undefined =
      profile && selectedVariant && selectedAddress && selectedPatient
        ? {
            nurseName: profile.nurseName,
            nurseRating: profile.averageRating,
            nurseTotalReviews: profile.totalReviews,
            patientName: selectedPatient.displayName,
            variantLabel: selectedVariant.displayName,
            variantPriceUnit: selectedVariant.priceUnit,
            variantPrice: selectedVariant.priceIrr,
            addressTitle: selectedAddress.title,
            cityId: selectedAddress.cityId,
            cityNameFa: selectedAddress.cityNameFa,
            cityNameEn: selectedAddress.cityNameEn,
            districtId: selectedAddress.districtId,
            districtNameFa: selectedAddress.districtNameFa,
            districtNameEn: selectedAddress.districtNameEn,
            addressLine: selectedAddress.addressLine,
            postalCode: selectedAddress.postalCode,
            recipientName: selectedAddress.recipientName,
            recipientPhone: selectedAddress.recipientPhone,
          }
        : undefined;

    createRequest.mutate(
      {
        payload: {
          nurseId,
          variantId: formValues.variantId as number,
          patientId: formValues.patientId as number,
          customerAddressId: formValues.addressId as number,
          requestedDate: formValues.date,
          requestedTimeStart: `${formValues.timeStart}:00`,
          requestedTimeEnd: `${formValues.timeEnd}:00`,
          requiredCaregiverGender: formValues.gender as RequiredCaregiverGender,
          customerNotes: formValues.notes.trim() || null,
        },
        context,
      },
      {
        onSuccess: (dto) => router.push(`/${locale}${ROUTES.BOOKING_REQUEST_STATUS}/${dto.id}`),
        onError: (error) => setFormError(mapCreateError(error, t)),
      },
    );
  };

  return (
    <FormProvider {...form}>
      <Stack component="form" noValidate onSubmit={handleSubmit(submit)} sx={{ gap: 3 }}>
        {profile ? <NurseIdentityBar profile={profile} /> : null}

        <Box>
          <Typography variant="h5" component="h1">
            {t('request_title')}
          </Typography>
          <Typography variant="body2" sx={{ color: 'text.secondary' }}>
            {t('form_subtitle')}
          </Typography>
        </Box>

        <Box>
          <Typography variant="subtitle2" sx={{ fontWeight: 700, mb: 0.5 }}>
            {t('whathappens_title')}
          </Typography>
          <StepperHeader steps={[t('step_submitted'), t('step_awaiting'), t('step_payment')]} activeStep={0} />
        </Box>

        {/* Patient */}
        {patients.length === 0 ? (
          <FieldEmpty
            label={t('patient_label')}
            message={t('patient_empty')}
            ctaLabel={t('patient_add_cta')}
            onCta={() => router.push(`/${locale}${ROUTES.PATIENTS}`)}
          />
        ) : (
          <RhfTextField<RequestFormValues>
            name="patientId"
            select
            label={t('patient_label')}
            rules={{ validate: (value) => value !== '' || t('error_patient_required') }}
            fullWidth
          >
            <MenuItem value="" disabled>
              {t('patient_placeholder')}
            </MenuItem>
            {patients.map((patient) => (
              <MenuItem key={patient.id} value={patient.id}>
                {patient.displayName}
              </MenuItem>
            ))}
          </RhfTextField>
        )}

        {/* Service variant */}
        <Stack sx={{ gap: 1 }}>
          {services.length === 0 ? (
            <Typography variant="body2" sx={{ color: 'text.secondary' }}>
              {t('service_empty')}
            </Typography>
          ) : (
            <RhfTextField<RequestFormValues>
              name="variantId"
              select
              label={t('service_label')}
              rules={{ validate: (value) => value !== '' || t('error_service_required') }}
              fullWidth
            >
              <MenuItem value="" disabled>
                {t('service_placeholder')}
              </MenuItem>
              {services.map((service) => (
                <MenuItem key={service.variantId} value={service.variantId}>
                  {service.displayName}
                </MenuItem>
              ))}
            </RhfTextField>
          )}
          {selectedVariant ? (
            <PriceDisplay
              price={selectedVariant.priceIrr}
              priceUnit={selectedVariant.priceUnit}
              sessionCount={selectedVariant.sessionCount}
            />
          ) : null}
        </Stack>

        {/* Address — a compact confirmation row once resolved, with a way back to the select. */}
        {addresses.length === 0 ? (
          <FieldEmpty
            label={t('address_label')}
            message={t('address_empty')}
            ctaLabel={t('address_add_cta')}
            onCta={() => router.push(`/${locale}${ROUTES.ADDRESSES}`)}
          />
        ) : addressEditing || !selectedAddress ? (
          <RhfTextField<RequestFormValues>
            name="addressId"
            select
            label={t('address_label')}
            rules={{ validate: (value) => value !== '' || t('error_address_required') }}
            // Collapses back to the compact summary row once the menu closes — picking a different
            // address is the normal exit, and dismissing without picking leaves the current one shown.
            slotProps={{ select: { onClose: () => setAddressEditing(false) } }}
            fullWidth
          >
            <MenuItem value="" disabled>
              {t('address_placeholder')}
            </MenuItem>
            {addresses.map((address) => (
              <MenuItem key={address.id} value={address.id}>
                {address.title} · {locale === 'en' ? address.cityNameEn : address.cityNameFa}
              </MenuItem>
            ))}
          </RhfTextField>
        ) : (
          <Stack
            direction="row"
            sx={{
              gap: 1.5,
              alignItems: 'center',
              p: 1.5,
              border: '1px solid',
              borderColor: 'divider',
              borderRadius: 'var(--bal-radius-md)',
            }}
          >
            <AppIcon icon="location" size={20} color="var(--bal-text-secondary)" />
            <Stack sx={{ gap: 0.25, minWidth: 0, flexGrow: 1 }}>
              <Typography variant="body2" sx={{ fontWeight: 500 }} noWrap>
                {regionLabel(selectedAddress)}
              </Typography>
              {selectedAddress.addressLine ? (
                <Typography variant="caption" sx={{ color: 'text.secondary' }} noWrap>
                  {selectedAddress.addressLine}
                </Typography>
              ) : null}
            </Stack>
            <AppButton variant="text" size="small" onClick={() => setAddressEditing(true)} sx={{ flexShrink: 0 }}>
              {t('address_change_cta')}
            </AppButton>
          </Stack>
        )}

        {/* Date — the past-date guard is a cross-field rule against the chosen start time. */}
        <RhfControlGroup<RequestFormValues>
          name="date"
          label={t('date_label')}
          rules={{
            validate: {
              chosen: (value) => value !== '' || t('error_date_required'),
              future: (value, all) =>
                !all.timeStart || Date.parse(`${value}T${all.timeStart}`) >= Date.now() || t('error_past_date'),
            },
          }}
        >
          {({ field }) => (
            <JalaliDateIntentPicker
              value={(field.value as string) ?? ''}
              onChange={field.onChange}
              min={todayIso()}
              todayLabel={t('date_today')}
              tomorrowLabel={t('date_tomorrow')}
              pickOtherLabel={t('date_pick_other')}
            />
          )}
        </RhfControlGroup>

        {/* Time window — presets kill the end<=start error class; «زمان دلخواه» reveals free time fields. */}
        <Stack sx={{ gap: 1 }}>
          <Typography variant="subtitle2" sx={{ fontWeight: 700 }}>
            {t('time_window_label')}
          </Typography>
          <Stack direction="row" sx={{ gap: 1, flexWrap: 'wrap' }}>
            {TIME_WINDOWS.map((option) => (
              <Chip
                key={option.key}
                clickable
                label={t(`window_${option.key}`)}
                onClick={() => selectWindow(option)}
                color={windowSel === option.key ? 'primary' : undefined}
                variant={windowSel === option.key ? 'filled' : 'outlined'}
                data-window={option.key}
              />
            ))}
            <Chip
              clickable
              label={t('window_custom')}
              onClick={() => setValue('window', 'custom', { shouldDirty: true })}
              color={windowSel === 'custom' ? 'primary' : undefined}
              variant={windowSel === 'custom' ? 'filled' : 'outlined'}
              data-window="custom"
            />
          </Stack>
          {windowSel === 'custom' ? (
            <Stack direction={{ xs: 'column', sm: 'row' }} sx={{ gap: 2 }}>
              <RhfTextField<RequestFormValues>
                name="timeStart"
                type="time"
                label={t('time_start_label')}
                rules={{ validate: (value) => value !== '' || t('error_time_required') }}
                slotProps={{ inputLabel: { shrink: true } }}
                fullWidth
              />
              <RhfTextField<RequestFormValues>
                name="timeEnd"
                type="time"
                label={t('time_end_label')}
                rules={{
                  validate: {
                    chosen: (value) => value !== '' || t('error_time_required'),
                    after: (value, all) => !all.timeStart || String(value) > all.timeStart || t('error_time_range'),
                  },
                }}
                slotProps={{ inputLabel: { shrink: true } }}
                fullWidth
              />
            </Stack>
          ) : null}
        </Stack>

        {/* Caregiver gender — first-class, three-way, never silently defaulted */}
        <RhfControlGroup<RequestFormValues>
          name="gender"
          label={t('gender_label')}
          hint={t('gender_hint')}
          rules={{ validate: (value) => value !== '' || t('error_gender_required') }}
        >
          {({ field, hasError }) => (
            <ToggleButtonGroup
              exclusive
              color="primary"
              value={field.value || null}
              onChange={(_event, next: RequiredCaregiverGender | null) => {
                if (next) field.onChange(next);
              }}
              sx={{
                '& .MuiToggleButton-root': {
                  flex: 1,
                  py: 1.25,
                  fontWeight: 700,
                  borderColor: hasError ? 'var(--bal-error)' : undefined,
                },
              }}
            >
              {GENDER_OPTIONS.map((option) => (
                <ToggleButton key={option} value={option} data-gender={option}>
                  {t(`gender_${option}`)}
                </ToggleButton>
              ))}
            </ToggleButtonGroup>
          )}
        </RhfControlGroup>

        {genderMismatch ? (
          <Typography variant="caption" sx={{ color: 'var(--bal-error)' }}>
            {t('error_gender_mismatch')}
          </Typography>
        ) : null}

        {/* Stage-1 notes */}
        <Stack sx={{ gap: 0.5 }}>
          <RhfTextField<RequestFormValues>
            name="notes"
            label={t('notes_label')}
            placeholder={t('notes_placeholder')}
            helperText={t('notes_hint')}
            transform={(raw) => raw.slice(0, CUSTOMER_NOTES_MAX_LENGTH)}
            multiline
            minRows={3}
            fullWidth
          />
          <Typography variant="caption" sx={{ color: 'text.secondary', textAlign: 'end' }}>
            {t('notes_counter', { count: notes.length, max: CUSTOMER_NOTES_MAX_LENGTH })}
          </Typography>
        </Stack>

        {formError ? (
          <Typography variant="body2" sx={{ color: 'var(--bal-error)' }}>
            {formError}
          </Typography>
        ) : null}

        <Stack sx={{ gap: 1 }}>
          <AppButton
            type="submit"
            color="primary"
            variant="contained"
            size="large"
            startIcon="requests"
            disabled={!requiredChosen || genderMismatch || createRequest.isPending}
            sx={{ py: 1.5 }}
          >
            {createRequest.isPending ? t('submitting') : t('submit')}
          </AppButton>
          {!requiredChosen ? (
            <Typography variant="caption" sx={{ color: 'text.secondary', textAlign: 'center' }}>
              {t('cta_missing_caption', { fields: missingFieldLabels.join(locale === 'fa' ? '، ' : ', ') })}
            </Typography>
          ) : null}
        </Stack>
      </Stack>
    </FormProvider>
  );
}

/** The sticky "who you're inviting home" identity summary — avatar, name, rating, trust badge, gender. */
function NurseIdentityBar({ profile }: { profile: NurseProfile }) {
  const t = useTranslations('booking');
  const locale = useLocale();
  const name = profile.nurseName.trim() || t('unnamed_nurse');
  const ratingLabel = formatNumber(profile.averageRating, locale, {
    minimumFractionDigits: 1,
    maximumFractionDigits: 1,
  });

  return (
    <Stack
      direction="row"
      data-nurse-identity-bar
      sx={{
        position: 'sticky',
        // Sticks just below the shell's pinned header rather than behind it (AppFrame publishes the
        // height); `0px` in a chrome-free shell.
        top: 'var(--bal-chrome-top, 0px)',
        zIndex: 2,
        gap: 1.5,
        alignItems: 'center',
        p: 1.5,
        border: '1px solid',
        borderColor: 'divider',
        borderRadius: 'var(--bal-radius-md)',
        bgcolor: 'background.paper',
      }}
    >
      <Avatar
        src={profile.avatarUrl ?? undefined}
        sx={{ width: 44, height: 44, bgcolor: 'var(--bal-primary-soft)', color: 'var(--bal-primary)', fontWeight: 700 }}
      >
        {name.charAt(0)}
      </Avatar>
      <Stack sx={{ gap: 0.25, minWidth: 0, flexGrow: 1 }}>
        <Stack direction="row" sx={{ gap: 1, alignItems: 'center', flexWrap: 'wrap' }}>
          <Typography variant="subtitle1" sx={{ fontWeight: 700 }} noWrap>
            {name}
          </Typography>
          <TrustBadge state={profile.isVerified ? 'verified' : 'unverified'} />
        </Stack>
        <Stack direction="row" sx={{ gap: 1, alignItems: 'center', flexWrap: 'wrap' }}>
          <Stack direction="row" sx={{ gap: 0.5, alignItems: 'center' }}>
            <AppIcon icon="star" size={15} color="var(--bal-rating)" />
            <Typography variant="caption" sx={{ fontWeight: 700 }}>
              {ratingLabel}
            </Typography>
            <Typography variant="caption" sx={{ color: 'text.secondary' }}>
              ({formatNumber(profile.totalReviews, locale)})
            </Typography>
          </Stack>
          <Chip
            size="small"
            variant="outlined"
            label={t(`gender_${profile.nurseGender}`)}
            sx={{ height: 20, fontSize: '0.7rem' }}
          />
        </Stack>
      </Stack>
    </Stack>
  );
}

/** Map a create `ApiError` (domain 400/404 codes) to a translated, user-facing message. */
function mapCreateError(error: unknown, t: (key: string) => string): string {
  if (error instanceof ApiError) {
    switch (error.code) {
      case 'gender_required':
        return t('error_gender_required');
      case 'invalid_time_range':
        return t('error_time_range');
      case 'past_date':
        return t('error_past_date');
      case 'notes_too_long':
        return t('error_notes_long');
      case 'gender_mismatch':
        return t('error_gender_mismatch');
      case 'inactive_variant':
      case 'not_bookable':
        return t('error_not_bookable');
      case 'not_found':
        return t('error_tenancy');
      default:
        break;
    }
    if (error.status === 404) return t('error_tenancy');
  }
  return t('error_generic');
}

function FieldEmpty({
  label,
  message,
  ctaLabel,
  onCta,
}: {
  label: string;
  message: string;
  ctaLabel: string;
  onCta: () => void;
}) {
  return (
    <Stack sx={{ gap: 0.5 }}>
      <Typography variant="subtitle2" sx={{ fontWeight: 700 }}>
        {label}
      </Typography>
      <EmptyState
        title={message}
        action={
          <AppButton variant="outlined" color="primary" startIcon="add" onClick={onCta}>
            {ctaLabel}
          </AppButton>
        }
      />
    </Stack>
  );
}

function FormSkeleton() {
  return (
    <Stack sx={{ gap: 2.5 }}>
      <Skeleton variant="rounded" height={76} />
      <Skeleton variant="text" width="50%" height={36} />
      <Skeleton variant="rounded" height={48} />
      {[0, 1, 2, 3].map((key) => (
        <Skeleton key={key} variant="rounded" height={56} />
      ))}
      <Skeleton variant="rounded" height={96} />
    </Stack>
  );
}
