'use client';

import { useState } from 'react';
import { Pencil, RefreshCw } from 'lucide-react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';

import { Button } from '@/components/ui/button';
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
} from '@/components/ui/dialog';
import { Label } from '@/components/ui/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Textarea } from '@/components/ui/textarea';
import { DetailHeaderStrip } from '@/components/shared/detail-header-strip';
import { PermissionGate } from '@/components/shared/permission-gate';
import { BerthForm } from './berth-form';
import { mooringLetterDot } from './mooring-letter-tone';
import { apiFetch } from '@/lib/api/client';
import { toastError } from '@/lib/api/toast-error';
import { useVocabulary } from '@/hooks/use-vocabulary';
import { updateBerthStatusSchema, type UpdateBerthStatusInput } from '@/lib/validators/berths';
import { BERTH_STATUSES } from '@/lib/constants';

type BerthDetailData = {
  id: string;
  mooringNumber: string;
  area: string | null;
  status: string;
  portId: string;
  lengthFt: string | null;
  lengthM: string | null;
  widthFt: string | null;
  widthM: string | null;
  draftFt: string | null;
  draftM: string | null;
  widthIsMinimum: boolean | null;
  nominalBoatSize: string | null;
  nominalBoatSizeM: string | null;
  waterDepth: string | null;
  waterDepthM: string | null;
  waterDepthIsMinimum: boolean | null;
  sidePontoon: string | null;
  cleatType: string | null;
  cleatCapacity: string | null;
  bollardType: string | null;
  bollardCapacity: string | null;
  bowFacing: string | null;
  price: string | null;
  priceCurrency: string;
  tenureType: string;
  tenureYears: number | null;
  tenureStartDate: string | null;
  tenureEndDate: string | null;
  powerCapacity: string | null;
  voltage: string | null;
  mooringType: string | null;
  access: string | null;
  berthApproved: boolean | null;
  tags: Array<{ id: string; name: string; color: string }>;
};

interface BerthDetailHeaderProps {
  berth: BerthDetailData;
}

const STATUS_COLORS: Record<string, string> = {
  available: 'bg-green-100 text-green-800 border-green-300',
  under_offer: 'bg-yellow-100 text-yellow-800 border-yellow-300',
  sold: 'bg-red-100 text-red-800 border-red-300',
};

const STATUS_LABELS: Record<string, string> = {
  available: 'Available',
  under_offer: 'Under Offer',
  sold: 'Sold',
};

interface InterestOption {
  id: string;
  clientName: string;
  pipelineStage: string;
}

function StatusChangeDialog({
  berthId,
  currentStatus,
  open,
  onOpenChange,
}: {
  berthId: string;
  currentStatus: string;
  open: boolean;
  onOpenChange: (open: boolean) => void;
}) {
  const queryClient = useQueryClient();
  const reasonChips = useVocabulary('berth_status_change_reasons');
  const {
    register,
    handleSubmit,
    setValue,
    watch,
    reset,
    formState: { isSubmitting },
  } = useForm<UpdateBerthStatusInput>({
    resolver: zodResolver(updateBerthStatusSchema),
    defaultValues: { status: currentStatus as (typeof BERTH_STATUSES)[number], reason: '' },
  });

  const status = watch('status');
  const interestId = watch('interestId');
  const showInterestPicker = status === 'under_offer' || status === 'sold';

  // Active interests for this port — used to populate the prospect
  // selector when status moves to under_offer / sold. Only fetched when
  // the picker is actually visible to avoid an unnecessary round-trip
  // for available-status changes.
  const interestsQuery = useQuery<{
    data: Array<{ id: string; clientName: string; pipelineStage: string }>;
  }>({
    queryKey: ['interests', 'status-link-picker'],
    queryFn: () => apiFetch('/api/v1/interests?pageSize=200'),
    enabled: open && showInterestPicker,
    staleTime: 60_000,
  });
  const interestOptions: InterestOption[] = interestsQuery.data?.data ?? [];

  async function onSubmit(data: UpdateBerthStatusInput) {
    try {
      await apiFetch(`/api/v1/berths/${berthId}/status`, {
        method: 'PATCH',
        body: data,
      });
      queryClient.invalidateQueries({ queryKey: ['berths'] });
      queryClient.invalidateQueries({ queryKey: ['berth', berthId] });
      queryClient.invalidateQueries({ queryKey: ['interests'] });
      toast.success('Status updated');
      reset();
      onOpenChange(false);
    } catch (err: unknown) {
      toastError(err);
    }
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-md">
        <DialogHeader>
          <DialogTitle>Change Status</DialogTitle>
        </DialogHeader>
        <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
          <div className="space-y-2">
            <Label>New Status</Label>
            <Select
              value={status}
              onValueChange={(v) => {
                setValue('status', v as (typeof BERTH_STATUSES)[number]);
                // Clear the interest pick when moving back to available so
                // a stale value doesn't sneak through on submit.
                if (v === 'available') setValue('interestId', undefined);
              }}
            >
              <SelectTrigger>
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                {BERTH_STATUSES.map((s) => (
                  <SelectItem key={s} value={s}>
                    {STATUS_LABELS[s]}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div className="space-y-2">
            <Label>Reason *</Label>
            {reasonChips.length > 0 && (
              <div className="flex flex-wrap gap-1.5">
                {reasonChips.map((chip) => (
                  <button
                    type="button"
                    key={chip}
                    onClick={() => setValue('reason', chip, { shouldDirty: true })}
                    className="rounded-full border border-muted-foreground/20 bg-muted px-2.5 py-0.5 text-xs hover:bg-accent"
                  >
                    {chip}
                  </button>
                ))}
              </div>
            )}
            <Textarea {...register('reason')} placeholder="Reason for status change..." rows={3} />
          </div>
          {showInterestPicker && (
            <div className="space-y-2">
              <Label>Linked prospect (optional)</Label>
              <Select
                value={interestId ?? '__none__'}
                onValueChange={(v) => setValue('interestId', v === '__none__' ? undefined : v)}
              >
                <SelectTrigger>
                  <SelectValue placeholder="Select an interest…" />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="__none__">— No interest —</SelectItem>
                  {interestOptions.map((opt) => (
                    <SelectItem key={opt.id} value={opt.id}>
                      {opt.clientName} · {opt.pipelineStage}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
              <p className="text-xs text-muted-foreground">
                Picking an interest auto-creates a primary berth link if one doesn&apos;t already
                exist, so the deal timeline + heat scorer attribute the change correctly.
              </p>
            </div>
          )}
          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
              Cancel
            </Button>
            <Button type="submit" disabled={isSubmitting}>
              {isSubmitting ? 'Saving...' : 'Update Status'}
            </Button>
          </DialogFooter>
        </form>
      </DialogContent>
    </Dialog>
  );
}

export function BerthDetailHeader({ berth }: BerthDetailHeaderProps) {
  const [editOpen, setEditOpen] = useState(false);
  const [statusOpen, setStatusOpen] = useState(false);

  return (
    <>
      <DetailHeaderStrip>
        {/* Stacks vertically on phone widths so the action buttons don't
            squeeze the area subtitle into a two-line wrap. From sm up the
            title/area block sits side-by-side with the action buttons. */}
        <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:gap-4">
          <div className="flex-1 min-w-0">
            <div className="flex items-center gap-3 flex-wrap">
              <h1 className="text-xl sm:text-2xl font-bold text-foreground">
                Berth {berth.mooringNumber}
              </h1>
              <span
                className={`inline-flex items-center rounded-full border px-3 py-1 text-sm font-medium ${STATUS_COLORS[berth.status] ?? 'bg-muted text-muted-foreground border-muted'}`}
              >
                {STATUS_LABELS[berth.status] ?? berth.status}
              </span>
            </div>
            {berth.area && (
              <div className="mt-2">
                <span
                  className={`inline-flex items-center gap-1.5 rounded-full px-3 py-0.5 text-xs font-semibold uppercase tracking-wide text-white ${mooringLetterDot(berth.mooringNumber) ?? 'bg-slate-400'}`}
                >
                  {berth.area} Dock
                </span>
              </div>
            )}
          </div>

          <div className="flex flex-wrap items-center gap-2 sm:shrink-0">
            <PermissionGate resource="berths" action="edit">
              <Button variant="outline" size="sm" onClick={() => setStatusOpen(true)}>
                <RefreshCw className="mr-1.5 h-4 w-4" />
                Change Status
              </Button>
              <Button size="sm" onClick={() => setEditOpen(true)}>
                <Pencil className="mr-1.5 h-4 w-4" />
                Edit
              </Button>
            </PermissionGate>
          </div>
        </div>
      </DetailHeaderStrip>

      <BerthForm berth={berth} open={editOpen} onOpenChange={setEditOpen} />

      <StatusChangeDialog
        berthId={berth.id}
        currentStatus={berth.status}
        open={statusOpen}
        onOpenChange={setStatusOpen}
      />
    </>
  );
}
