'use client';
import { FunctionComponent } from 'react';
import { useLocale, useTranslations } from 'next-intl';
import { Avatar, Chip, Paper, Skeleton, Stack, Typography } from '@mui/material';
import AccentCard from '@/components/common/AccentCard';
import AppButton from '@/components/common/AppButton';
import AppIcon from '@/components/common/AppIcon';
import SurfaceCard from '@/components/common/SurfaceCard';
import { formatRelativeTime, formatShamsiDate, localeTag } from '@/utils';
import { useBookingDetail, useCareInstructions } from '@/services/bookings';
import {
  isBookingConfirmedOrBeyond,
  type BookingDetailDto,
  type BookingSessionDto,
  type BookingViewerRole,
} from '@/services/bookings/types';
import BookingStatusTimeline from '../BookingStatusTimeline';
import SessionList from '../SessionList';
import BookingMoneySummary from '../BookingMoneySummary';
import CareInstructionsCard from '../CareInstructionsCard';
import CheckOutConfirmButton from '../CheckOutConfirmButton';
import { useEvvController } from '../useEvvController';
import { buildSessionIcs, downloadIcsFile } from '../ics';
import { formatElapsed } from '../format';

export interface BookingDetailViewProps {
  bookingId: number;
  /** `customer` sees the read-only timeline + sessions + money; `nurse` adds EVV controls + gated care. */
  viewerRole: BookingViewerRole;
}

/** Best-effort read of the frozen variant display name from the booking's variant snapshot. */
function variantName(snapshotJson: string): string | null {
  try {
    const parsed = JSON.parse(snapshotJson) as { displayName?: string };
    return parsed?.displayName ?? null;
  } catch {
    return null;
  }
}

/**
 * Best-effort read of the frozen address snapshot. The wire has no stable schema for this blob
 * (confirmed against the seed fixtures — field names drift between `city`/`cityName`/`cityNameFa` and
 * `line`/`addressLine` across bookings) — REQ-045 proposes a typed shape; until then this tries every
 * candidate key and joins whatever resolves. `null` for the nurse view (masked server-side) or a
 * genuinely empty snapshot.
 */
function addressSnapshotLabel(snapshotJson: string | null, locale: string): string | null {
  if (!snapshotJson) return null;
  try {
    const parsed = JSON.parse(snapshotJson) as Record<string, string | undefined>;
    const city = locale === 'en' ? (parsed.cityNameEn ?? parsed.cityName ?? parsed.city) : (parsed.cityNameFa ?? parsed.cityName ?? parsed.city);
    const district = locale === 'en' ? (parsed.districtNameEn ?? parsed.district) : (parsed.districtNameFa ?? parsed.district);
    const parts = [parsed.title, city, district, parsed.addressLine ?? parsed.line].filter(
      (part): part is string => Boolean(part && part.trim()),
    );
    return parts.length > 0 ? parts.join(' · ') : null;
  } catch {
    return null;
  }
}

/** The earliest not-yet-finished session — the "next visit" the hero headlines. */
function upcomingSession(sessions: BookingSessionDto[]): BookingSessionDto | undefined {
  return sessions.find((session) => session.status === 'scheduled' || session.status === 'in_progress');
}

/** The session currently checked in (on-site) — drives the EVV presence headline + the in-visit banner. */
function checkedInSession(sessions: BookingSessionDto[]): BookingSessionDto | undefined {
  return sessions.find((session) => session.evvStatus === 'checked_in');
}

/**
 * Best-effort lat/lng off the same untyped address snapshot `addressSnapshotLabel` reads (REQ-045 proposes
 * a typed shape). `null` when absent — the map link is a quiet enhancement, never required.
 */
function addressSnapshotCoords(snapshotJson: string | null): { lat: number; lng: number } | null {
  if (!snapshotJson) return null;
  try {
    const parsed = JSON.parse(snapshotJson) as Record<string, unknown>;
    const lat = Number(parsed.latitude ?? parsed.lat);
    const lng = Number(parsed.longitude ?? parsed.lng);
    return Number.isFinite(lat) && Number.isFinite(lng) ? { lat, lng } : null;
  } catch {
    return null;
  }
}

const NESHAN_MAP_ZOOM = 16;

/** A `geo:` URI — the mobile-native map-app intent (Android resolves it directly). */
function buildGeoUri(lat: number, lng: number): string {
  return `geo:${lat},${lng}?q=${lat},${lng}`;
}

/** The web fallback for platforms with no `geo:` handler (desktop, iOS Safari) — link only, no SDK/API key. */
function buildNeshanWebUrl(lat: number, lng: number): string {
  return `https://neshan.org/maps/@${lat},${lng},${NESHAN_MAP_ZOOM}z`;
}

/**
 * The both-roles booking detail — the hinge screen. Fetches `useBookingDetail`, renders the server-truth
 * `BookingStatusTimeline`, the `SessionList`, and the `BookingMoneySummary`. Role-conditioned: the
 * **assigned nurse** additionally gets the per-session EVV controls and the gated `CareInstructionsCard`;
 * the **customer** sees the read-only view and a "visible to your nurse only" affordance in place of the
 * clinical record.
 *
 * **Two-stage disclosure is a hard UI gate:** the care-instructions query is `enabled` **only** for the
 * nurse view on a `confirmed`+ booking — for the customer it never fires (a 404 would be a defect path,
 * not the design). Money is display-only; the timeline is never advanced client-side.
 * @component BookingDetailView
 */
const BookingDetailView: FunctionComponent<BookingDetailViewProps> = ({ bookingId, viewerRole }) => {
  const t = useTranslations('booking');
  const locale = useLocale();
  const isNurse = viewerRole === 'nurse';

  const { data: booking, isLoading, isError } = useBookingDetail(bookingId, viewerRole);
  const careEnabled = isNurse && !!booking && isBookingConfirmedOrBeyond(booking.status);
  const care = useCareInstructions(bookingId, { enabled: careEnabled });
  const evv = useEvvController();

  if (isLoading) return <DetailSkeleton />;
  if (isError || !booking) return <NotFoundCard title={t('bd_not_found_title')} body={t('bd_not_found_body')} />;

  const service = variantName(booking.variantSnapshotJson);
  const addressLabel = addressSnapshotLabel(booking.addressSnapshotJson, locale);
  const nextSession = upcomingSession(booking.sessions);
  const checkedIn = checkedInSession(booking.sessions);
  const onSiteCheckInAt = checkedIn?.checkInAt ?? null;
  const clockFmt = new Intl.DateTimeFormat(localeTag(locale), { hour: '2-digit', minute: '2-digit' });

  const nextSessionDayLabel = nextSession
    ? formatRelativeTime(`${nextSession.scheduledDate}T${nextSession.scheduledTimeStart}`, locale, formatShamsiDate)
    : null;
  const nextSessionTimeLabel = nextSession
    ? clockFmt.format(new Date(`${nextSession.scheduledDate}T${nextSession.scheduledTimeStart}`))
    : null;

  const addToCalendar = () => {
    if (!nextSession) return;
    const start = new Date(`${nextSession.scheduledDate}T${nextSession.scheduledTimeStart}`);
    const end = new Date(`${nextSession.scheduledDate}T${nextSession.scheduledTimeEnd}`);
    const ics = buildSessionIcs({
      uid: `balinyaar-booking-${booking.id}-session-${nextSession.id}@balinyaar`,
      title: `${service ?? t('bd_title')} — ${t('session_index', { n: nextSession.sessionIndex })}`,
      location: addressLabel ?? undefined,
      start,
      end,
    });
    downloadIcsFile(`balinyaar-booking-${booking.id}-visit-${nextSession.sessionIndex}.ics`, ics);
  };

  return (
    <Stack sx={{ gap: 3, maxWidth: 640, mx: 'auto', width: '100%' }} data-viewer-role={viewerRole}>
      {/* Hero — next-visit headline, address, nurse identity, add-to-calendar; terracotta accent + "نمای
          پرستار" chip on the nurse view. */}
      <Paper
        elevation={0}
        sx={{
          p: 2.5,
          border: '1px solid',
          borderColor: 'divider',
          borderRadius: 'var(--bal-radius-md)',
          ...(isNurse ? { borderTopWidth: 3, borderTopColor: 'var(--bal-secondary)' } : {}),
        }}
      >
        <Stack sx={{ gap: 1.5 }}>
          <Stack direction="row" sx={{ justifyContent: 'space-between', alignItems: 'flex-start', gap: 1.5, flexWrap: 'wrap' }}>
            <Stack sx={{ gap: 0.25 }}>
              <Typography variant="h6" component="h1">
                {nextSession ? (
                  <>
                    {t('session_index', { n: nextSession.sessionIndex })} · {nextSessionDayLabel}{' '}
                    <Typography component="span" dir="ltr" sx={{ fontVariantNumeric: 'tabular-nums' }}>
                      {nextSessionTimeLabel}
                    </Typography>
                  </>
                ) : (
                  (service ?? t('bd_title'))
                )}
              </Typography>
              <Typography variant="caption" sx={{ color: 'text.secondary' }}>
                {t('bd_ref', { id: booking.id })}
              </Typography>
            </Stack>
            {isNurse ? (
              <Chip
                size="small"
                label={t('evv_nurse_view')}
                sx={{ bgcolor: 'var(--bal-secondary-soft)', color: 'var(--bal-secondary-dark)', fontWeight: 700 }}
              />
            ) : null}
          </Stack>

          {onSiteCheckInAt ? (
            <Stack
              direction="row"
              sx={{ gap: 1, alignItems: 'center', px: 1.5, py: 1, borderRadius: 'var(--bal-radius-md)', bgcolor: 'var(--bal-success-soft)' }}
            >
              <AppIcon icon="location" size={18} color="var(--bal-success)" />
              <Typography variant="body2" sx={{ fontWeight: 700, color: 'var(--bal-success)' }}>
                {t('evv_presence_headline', { time: clockFmt.format(new Date(onSiteCheckInAt)) })}
              </Typography>
            </Stack>
          ) : null}

          <Stack direction="row" sx={{ gap: 1.5, alignItems: 'center', flexWrap: 'wrap' }}>
            <Avatar sx={{ width: 36, height: 36, bgcolor: 'var(--bal-primary-soft)', color: 'var(--bal-primary)', fontWeight: 700 }}>
              {(booking.nurseName.trim() || t('unnamed_nurse')).charAt(0)}
            </Avatar>
            <HeaderFact label={t('bd_nurse_label')} value={booking.nurseName} />
            <HeaderFact label={t('summary_patient')} value={booking.patientName} />
          </Stack>

          {nextSession ? (
            <AppButton
              variant="outlined"
              color="primary"
              size="small"
              startIcon="calendar"
              onClick={addToCalendar}
              sx={{ alignSelf: 'flex-start' }}
            >
              {t('bd_add_to_calendar')}
            </AppButton>
          ) : null}
        </Stack>
      </Paper>

      <AddressCard addressSnapshotJson={booking.addressSnapshotJson} viewerRole={viewerRole} locale={locale} />

      {isNurse && checkedIn ? (
        <InVisitBanner
          checkInAt={checkedIn.checkInAt as string}
          locale={locale}
          busy={evv.busySessionId === checkedIn.id}
          acquiringLocation={evv.acquiringSessionId === checkedIn.id}
          onCheckOut={() => evv.checkOut({ sessionId: checkedIn.id, bookingId: booking.id })}
        />
      ) : null}

      <SurfaceCard>
        <BookingStatusTimeline status={booking.status} />
      </SurfaceCard>

      <StatusNote booking={booking} />

      <Stack sx={{ gap: 1.5 }}>
        <Typography variant="subtitle1" sx={{ fontWeight: 700 }}>
          {t('sessions_title')}
        </Typography>
        <SessionList
          sessions={booking.sessions}
          showEvvControls={isNurse}
          showPayout={isNurse}
          busySessionId={evv.busySessionId}
          acquiringSessionId={evv.acquiringSessionId}
          onCheckIn={isNurse ? (s) => evv.checkIn({ sessionId: s.id, bookingId: booking.id }) : undefined}
          onCheckOut={isNurse ? (s) => evv.checkOut({ sessionId: s.id, bookingId: booking.id }) : undefined}
        />
      </Stack>

      <BookingMoneySummary
        grossPriceIrr={booking.grossPriceIrr}
        balinyaarCommissionIrr={booking.balinyaarCommissionIrr}
        nursePayoutAmount={booking.nursePayoutAmount}
        viewerRole={viewerRole}
      />

      <CareSection viewerRole={viewerRole} careEnabled={careEnabled} care={care} />
    </Stack>
  );
};

/**
 * The frozen visit address — a map deep-link when the snapshot carries coordinates, a quiet fallback note
 * on the (currently masked, REQ-051-pending) nurse view instead of a hard error, and nothing at all when
 * there is genuinely no snapshot on the customer side (mock-tolerant: renders when present, degrades
 * quietly otherwise). Never sourced from the pre-payment (b8) request stage.
 */
function AddressCard({
  addressSnapshotJson,
  viewerRole,
  locale,
}: {
  addressSnapshotJson: string | null;
  viewerRole: BookingViewerRole;
  locale: string;
}) {
  const t = useTranslations('booking');
  const label = addressSnapshotLabel(addressSnapshotJson, locale);
  const coords = addressSnapshotCoords(addressSnapshotJson);
  const isNurse = viewerRole === 'nurse';

  if (!label) {
    if (!isNurse) return null;
    return (
      <AccentCard tone="neutral">
        <Stack direction="row" sx={{ gap: 1, alignItems: 'flex-start' }}>
          <AppIcon icon="location" size={18} color="var(--bal-text-secondary)" />
          <Typography variant="body2" sx={{ color: 'text.secondary' }}>
            {t('address_pending_note')}
          </Typography>
        </Stack>
      </AccentCard>
    );
  }

  return (
    <SurfaceCard>
      <Stack sx={{ gap: 1 }}>
        <Stack direction="row" sx={{ gap: 1, alignItems: 'center' }}>
          <AppIcon icon="location" size={18} color="var(--bal-primary)" />
          <Typography variant="subtitle2" sx={{ fontWeight: 700 }}>
            {t('address_title')}
          </Typography>
        </Stack>
        <Typography variant="body2" sx={{ color: 'text.secondary' }}>
          {label}
        </Typography>
        {coords ? (
          <Stack direction="row" sx={{ gap: 1, flexWrap: 'wrap' }}>
            <AppButton
              variant="outlined"
              color="primary"
              size="small"
              startIcon="navigate"
              href={buildGeoUri(coords.lat, coords.lng)}
              sx={{ alignSelf: 'flex-start' }}
            >
              {t('address_open_map')}
            </AppButton>
            <AppButton
              variant="text"
              color="primary"
              size="small"
              href={buildNeshanWebUrl(coords.lat, coords.lng)}
              openInNewTab
              sx={{ alignSelf: 'flex-start' }}
            >
              {t('address_open_web_map')}
            </AppButton>
          </Stack>
        ) : null}
      </Stack>
    </SurfaceCard>
  );
}

/**
 * The nurse-only "on site now" state header — promotes the check-out action above the session list (it
 * ends the visit and starts the payout clock) alongside elapsed on-site time. `checkInAt` is server truth;
 * the elapsed duration is computed against the render-time clock (never a guessed start).
 */
function InVisitBanner({
  checkInAt,
  locale,
  busy,
  acquiringLocation,
  onCheckOut,
}: {
  checkInAt: string;
  locale: string;
  busy: boolean;
  acquiringLocation: boolean;
  onCheckOut: () => void;
}) {
  const t = useTranslations('booking');
  const elapsed = formatElapsed(checkInAt, new Date().toISOString(), locale);

  return (
    <AccentCard tone="secondary">
      <Stack sx={{ gap: 1.5 }}>
        <Stack direction="row" sx={{ gap: 1.25, alignItems: 'center' }}>
          <AppIcon icon="check_in" size={20} color="var(--bal-secondary)" />
          <Stack sx={{ gap: 0.25 }}>
            <Typography variant="subtitle1" sx={{ fontWeight: 700 }}>
              {t('in_visit_title')}
            </Typography>
            {elapsed ? (
              <Typography variant="body2" sx={{ color: 'text.secondary' }}>
                {t('in_visit_elapsed', { duration: elapsed })}
              </Typography>
            ) : null}
          </Stack>
        </Stack>
        <CheckOutConfirmButton onConfirm={onCheckOut} busy={busy} acquiringLocation={acquiringLocation} fullWidth />
      </Stack>
    </AccentCard>
  );
}

function HeaderFact({ label, value }: { label: string; value: string }) {
  return (
    <Stack sx={{ gap: 0.25 }}>
      <Typography variant="caption" sx={{ color: 'text.secondary' }}>
        {label}
      </Typography>
      <Typography variant="body2" sx={{ fontWeight: 500 }}>
        {value}
      </Typography>
    </Stack>
  );
}

/** The per-status content note — confirmed/in-progress/completed(+dispute window)/disputed/cancelled. */
function StatusNote({ booking }: { booking: BookingDetailDto }) {
  const t = useTranslations('booking');
  const locale = useLocale();

  const lines: string[] = [];
  let tone: 'info' | 'warning' | 'neutral' = 'info';
  let icon = 'info';

  switch (booking.status) {
    case 'confirmed':
      lines.push(t('confirmed_note'));
      break;
    case 'in_progress':
      lines.push(t('in_progress_note'));
      break;
    case 'completed':
    case 'closed':
      lines.push(t('completed_note'));
      icon = 'verified';
      break;
    case 'disputed':
      lines.push(t('disputed_note'));
      tone = 'warning';
      icon = 'warning';
      break;
    case 'cancelled':
      lines.push(t('cancelled_note'));
      tone = 'neutral';
      icon = 'rejected';
      break;
    default:
      break;
  }

  if (booking.disputeWindowEndsAt && (booking.status === 'completed' || booking.status === 'closed')) {
    lines.push(t('dispute_window_note', { date: formatShamsiDate(booking.disputeWindowEndsAt, locale) }));
  }

  if (lines.length === 0) return null;

  const bg =
    tone === 'warning' ? 'var(--bal-secondary-soft)' : tone === 'neutral' ? 'var(--bal-divider)' : 'var(--bal-primary-soft)';
  const color = tone === 'warning' ? 'var(--bal-secondary-dark)' : 'var(--bal-text-secondary)';

  return (
    <Stack direction="row" sx={{ gap: 1, alignItems: 'flex-start', p: 1.5, borderRadius: 'var(--bal-radius-md)', bgcolor: bg }}>
      <AppIcon icon={icon} size={18} color={color} />
      <Stack sx={{ gap: 0.25 }}>
        {lines.map((line) => (
          <Typography key={line} variant="body2" sx={{ color: 'text.secondary' }}>
            {line}
          </Typography>
        ))}
      </Stack>
    </Stack>
  );
}

/** The care-instructions region — the gated nurse card, or the customer's "visible to your nurse" note. */
function CareSection({
  viewerRole,
  careEnabled,
  care,
}: {
  viewerRole: BookingViewerRole;
  careEnabled: boolean;
  care: ReturnType<typeof useCareInstructions>;
}) {
  const t = useTranslations('booking');

  if (viewerRole !== 'nurse') {
    // Customer: never renders the clinical record and never fires the query.
    return (
      <AccentCard tone="neutral">
        <Stack direction="row" sx={{ gap: 1.25, alignItems: 'flex-start' }}>
          <AppIcon icon="lock" size={20} color="var(--bal-text-secondary)" />
          <Stack sx={{ gap: 0.25 }}>
            <Typography variant="subtitle2" sx={{ fontWeight: 700 }}>
              {t('care_locked_title')}
            </Typography>
            <Typography variant="body2" sx={{ color: 'text.secondary' }}>
              {t('care_locked_body')}
            </Typography>
          </Stack>
        </Stack>
      </AccentCard>
    );
  }

  if (!careEnabled) return null;
  if (care.isLoading) return <Skeleton variant="rounded" height={180} />;
  if (care.isError || !care.data) {
    return (
      <Paper elevation={0} sx={{ p: 2.5, border: '1px solid', borderColor: 'divider', borderRadius: 'var(--bal-radius-md)' }}>
        <Typography variant="body2" sx={{ color: 'text.secondary' }}>
          {t('care_error')}
        </Typography>
      </Paper>
    );
  }
  return <CareInstructionsCard data={care.data} />;
}

function NotFoundCard({ title, body }: { title: string; body: string }) {
  return (
    <Paper
      elevation={0}
      sx={{ p: 4, textAlign: 'center', border: '1px solid', borderColor: 'divider', borderRadius: 'var(--bal-radius-md)', maxWidth: 640, mx: 'auto' }}
    >
      <AppIcon icon="error" size={44} color="var(--bal-text-secondary)" />
      <Typography variant="subtitle1" sx={{ fontWeight: 700, mt: 1, mb: 0.5 }}>
        {title}
      </Typography>
      <Typography variant="body2" sx={{ color: 'text.secondary' }}>
        {body}
      </Typography>
    </Paper>
  );
}

function DetailSkeleton() {
  return (
    <Stack sx={{ gap: 3, maxWidth: 640, mx: 'auto', width: '100%' }}>
      <Skeleton variant="rounded" height={110} />
      <Skeleton variant="rounded" height={96} />
      <Skeleton variant="rounded" height={72} />
      <Skeleton variant="rounded" height={140} />
      <Skeleton variant="rounded" height={120} />
    </Stack>
  );
}

export default BookingDetailView;
