'use client';

import { useEffect, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';

import { cn } from '@/lib/utils';

import { type DetailTab } from '@/components/shared/detail-layout';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { EntityActivityFeed } from '@/components/shared/entity-activity-feed';
import { InlineEditableField } from '@/components/shared/inline-editable-field';
import { InlineTagEditor } from '@/components/shared/inline-tag-editor';
import { apiFetch } from '@/lib/api/client';
import { formatCurrency } from '@/lib/utils/currency';
import {
  BERTH_ACCESS_OPTIONS,
  BERTH_BOLLARD_CAPACITIES,
  BERTH_BOLLARD_TYPES,
  BERTH_BOW_FACING_OPTIONS,
  BERTH_CLEAT_CAPACITIES,
  BERTH_CLEAT_TYPES,
  BERTH_MOORING_TYPES,
  BERTH_SIDE_PONTOON_OPTIONS,
  toSelectOptions,
} from '@/lib/constants';
import { BerthTenanciesTab } from './berth-tenancies-tab';
import { BerthInterestsTab } from './berth-interests-tab';
import { BerthInterestPulse } from './berth-interest-pulse';
import { BerthDocumentsTab } from './berth-documents-tab';
import { BerthDealDocumentsTab } from './berth-deal-documents-tab';
import { BerthMaintenanceTab } from './berth-maintenance-tab';
import { WaitingListManager } from './waiting-list-manager';

import type { BerthDetailData as BerthData } from './berth-detail-header';

/**
 * Compact ft/m segmented control for the Specifications card. Two
 * tappable pills with `min-h-[36px]` for an Apple-HIG-friendly touch
 * target. The active option gets the brand primary background; the
 * other reads as muted.
 */
function UnitToggle({ value, onChange }: { value: 'ft' | 'm'; onChange: (v: 'ft' | 'm') => void }) {
  return (
    <div
      role="tablist"
      aria-label="Display unit"
      className="inline-flex items-center gap-0.5 rounded-md border bg-muted/40 p-0.5 text-xs"
    >
      {(['ft', 'm'] as const).map((opt) => (
        <button
          key={opt}
          type="button"
          role="tab"
          aria-selected={value === opt}
          onClick={() => onChange(opt)}
          className={cn(
            'min-h-[28px] min-w-[40px] rounded px-2 font-medium transition-colors',
            value === opt
              ? 'bg-background text-foreground shadow-sm'
              : 'text-muted-foreground hover:text-foreground',
          )}
        >
          {opt}
        </button>
      ))}
    </div>
  );
}

function SpecRow({ label, value }: { label: string; value: React.ReactNode }) {
  if (!value && value !== 0 && value !== false) return null;
  // Mobile-first: stack vertically with label on top so long values
  // (e.g. "206.69 ft / 62.99 m") never clip at the right edge.
  // From `sm` (>=640px) up: switch to the original two-column layout.
  return (
    <div className="flex flex-col gap-0.5 py-2 text-sm sm:flex-row sm:items-baseline sm:justify-between sm:gap-3">
      <span className="text-muted-foreground">{label}</span>
      <span className="font-medium sm:max-w-[60%] sm:text-right">{value}</span>
    </div>
  );
}

/**
 * Tags Card for the berth overview. Wraps the InlineTagEditor in a Card so
 * the section header uses CardTitle styling; mirrors the visibility rule
 * the editor itself uses - hides entirely when the port has no tags
 * defined AND this berth has none applied.
 */
function BerthTagsCard({ berth }: { berth: BerthData }) {
  const { data: allTags } = useQuery<{ data: { id: string; name: string; color: string }[] }>({
    queryKey: ['tags'],
    queryFn: () => apiFetch('/api/v1/tags'),
    staleTime: 60_000,
  });
  const portHasNoTags = allTags && allTags.data.length === 0;
  if (portHasNoTags && berth.tags.length === 0) return null;
  return (
    <Card>
      <CardHeader className="pb-3">
        <CardTitle className="text-sm font-medium">Tags</CardTitle>
      </CardHeader>
      <CardContent className="pt-0">
        <InlineTagEditor
          endpoint={`/api/v1/berths/${berth.id}/tags`}
          currentTags={berth.tags}
          invalidateKey={['berths', berth.id]}
        />
      </CardContent>
    </Card>
  );
}

function useBerthPatch(berthId: string) {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: async (patch: Record<string, string | number | boolean | null>) =>
      apiFetch(`/api/v1/berths/${berthId}`, {
        method: 'PATCH',
        body: patch,
      }),
    onSuccess: () => {
      // Detail page query is keyed `['berth', berthId]` (singular); the
      // list query is `['berths']` (plural). Invalidate both so inline
      // edits on the detail Overview tab refresh the visible value
      // even when Socket.IO realtime isn't running (dev / no-ws envs).
      qc.invalidateQueries({ queryKey: ['berth', berthId] });
      qc.invalidateQueries({ queryKey: ['berths'] });
    },
  });
}

/**
 * Editable spec row. Wraps SpecRow with InlineEditableField for fields
 * the operator commonly tweaks (length, width, draft, side pontoon, etc).
 * Read-only fields (mooringNumber, area) keep using plain SpecRow.
 *
 * Numeric fields are stored as strings in the schema (postgres NUMERIC);
 * the `numeric` flag tells us to parse before sending and display "-" when
 * blank.
 */
function EditableSpec({
  label,
  value,
  displayValue,
  field,
  patch,
  numeric = false,
  suffix,
  selectOptions,
  linkedUnit,
}: {
  label: string;
  value: string | null;
  /** Optional formatted version for display only (currency, percent,
   *  unit-suffixed). The edit input still works against the raw `value`. */
  displayValue?: string | null;
  field: string;
  patch: ReturnType<typeof useBerthPatch>;
  numeric?: boolean;
  suffix?: string;
  /** When provided, the inline editor uses a `<Select>` constrained to these
   *  values. Mirrors the canonical NocoDB SingleSelect choices for the field. */
  selectOptions?: readonly string[];
  /** When set, saving this numeric field also patches the paired column with
   *  the converted unit (e.g. ft → m via 0.3048). Mirrors the legacy NocoDB
   *  Formula columns; without this the form's two-unit editors stay out of
   *  sync after an inline edit. */
  linkedUnit?: { field: string; multiplier: number };
}) {
  return (
    <div className="flex flex-col gap-0.5 py-2 text-sm sm:flex-row sm:items-baseline sm:justify-between sm:gap-3">
      <span className="text-muted-foreground">{label}</span>
      <span className="font-medium sm:max-w-[60%] sm:text-right">
        {selectOptions ? (
          <InlineEditableField
            variant="select"
            value={value}
            options={toSelectOptions(selectOptions)}
            onSave={async (next) => {
              await patch.mutateAsync({ [field]: next });
            }}
          />
        ) : (
          <InlineEditableField
            value={value}
            displayValue={displayValue}
            onSave={async (next) => {
              if (numeric) {
                if (next === null || next.trim() === '') {
                  const clear = linkedUnit
                    ? { [field]: null, [linkedUnit.field]: null }
                    : { [field]: null };
                  await patch.mutateAsync(clear);
                  return;
                }
                const n = Number.parseFloat(next);
                if (Number.isNaN(n)) throw new Error('Must be a number');
                const body: Record<string, number | null> = { [field]: n };
                if (linkedUnit) {
                  body[linkedUnit.field] = Number((n * linkedUnit.multiplier).toFixed(2));
                }
                await patch.mutateAsync(body);
                return;
              }
              await patch.mutateAsync({ [field]: next });
            }}
            placeholder={suffix ? `e.g. 25${suffix ? ` ${suffix}` : ''}` : undefined}
          />
        )}
      </span>
    </div>
  );
}

// Conversion factors between feet and meters. 0.3048 is the exact
// definition (1 ft = 0.3048 m by international agreement).
const FT_TO_M = 0.3048;
const M_TO_FT = 1 / FT_TO_M;

function OverviewTab({ berth }: { berth: BerthData }) {
  const patch = useBerthPatch(berth.id);
  // User-selected display unit for dimensions. Persisted in localStorage
  // so reps' preferred unit sticks across navigations + sessions.
  // Lazy initializer reads localStorage on first render - avoids the
  // mount-effect-setState shape the compiler flags.
  const [units, setUnits] = useState<'ft' | 'm'>(() => {
    if (typeof window === 'undefined') return 'ft';
    const stored = window.localStorage.getItem('berth-overview-units');
    return stored === 'ft' || stored === 'm' ? stored : 'ft';
  });
  useEffect(() => {
    localStorage.setItem('berth-overview-units', units);
  }, [units]);

  const u = units;
  // For each dimension, pick the column matching the selected unit and
  // point linkedUnit at the opposite column so edits keep both in sync.
  const dim = (ftField: string, mField: string) =>
    units === 'ft'
      ? { field: ftField, linkedUnit: { field: mField, multiplier: FT_TO_M } }
      : { field: mField, linkedUnit: { field: ftField, multiplier: M_TO_FT } };
  const dimValue = (ftValue: string | null, mValue: string | null) =>
    units === 'ft' ? ftValue : mValue;

  return (
    <div className="space-y-6">
      {/* Sales pulse - top-of-page so reps doing berth-level triage can see
          who's interested + how warm without clicking into the Interests tab. */}
      <BerthInterestPulse berthId={berth.id} />

      <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
        {/* Specifications */}
        <Card>
          <CardHeader className="flex flex-row items-center justify-between gap-2 pb-3">
            <CardTitle className="text-sm font-medium">Specifications</CardTitle>
            <UnitToggle value={units} onChange={setUnits} />
          </CardHeader>
          <CardContent className="pt-0 divide-y">
            <EditableSpec
              label={`Length (${u})`}
              value={dimValue(berth.lengthFt, berth.lengthM)}
              {...dim('lengthFt', 'lengthM')}
              patch={patch}
              numeric
              suffix={u}
            />
            <EditableSpec
              label={`Width (${u})`}
              value={dimValue(berth.widthFt, berth.widthM)}
              {...dim('widthFt', 'widthM')}
              patch={patch}
              numeric
              suffix={u}
            />
            <EditableSpec
              label={`Draft (${u})`}
              value={dimValue(berth.draftFt, berth.draftM)}
              {...dim('draftFt', 'draftM')}
              patch={patch}
              numeric
              suffix={u}
            />
            <EditableSpec
              label={`Nominal Boat Size (${u})`}
              value={dimValue(berth.nominalBoatSize, berth.nominalBoatSizeM)}
              {...dim('nominalBoatSize', 'nominalBoatSizeM')}
              patch={patch}
              numeric
              suffix={u}
            />
            <EditableSpec
              label={`Water Depth (${u})`}
              value={dimValue(berth.waterDepth, berth.waterDepthM)}
              {...dim('waterDepth', 'waterDepthM')}
              patch={patch}
              numeric
              suffix={u}
            />
            <EditableSpec
              label="Mooring Type"
              value={berth.mooringType}
              field="mooringType"
              patch={patch}
              selectOptions={BERTH_MOORING_TYPES}
            />
            <EditableSpec
              label="Side Pontoon"
              value={berth.sidePontoon}
              field="sidePontoon"
              patch={patch}
              selectOptions={BERTH_SIDE_PONTOON_OPTIONS}
            />
            <EditableSpec
              label="Bow Facing"
              value={berth.bowFacing}
              field="bowFacing"
              patch={patch}
              selectOptions={BERTH_BOW_FACING_OPTIONS}
            />
            <EditableSpec
              label="Access"
              value={berth.access}
              field="access"
              patch={patch}
              selectOptions={BERTH_ACCESS_OPTIONS}
            />
            <SpecRow label="Approved" value={berth.berthApproved ? 'Yes' : null} />
          </CardContent>
        </Card>

        {/* Infrastructure & Pricing */}
        <div className="space-y-6">
          <Card>
            <CardHeader className="pb-3">
              <CardTitle className="text-sm font-medium">Infrastructure</CardTitle>
            </CardHeader>
            <CardContent className="pt-0 divide-y">
              <EditableSpec
                label="Power Capacity (kW)"
                value={berth.powerCapacity}
                field="powerCapacity"
                patch={patch}
                numeric
                suffix="kW"
              />
              <EditableSpec
                label="Voltage (V)"
                value={berth.voltage}
                field="voltage"
                patch={patch}
                numeric
                suffix="V"
              />
              <EditableSpec
                label="Cleat Type"
                value={berth.cleatType}
                field="cleatType"
                patch={patch}
                selectOptions={BERTH_CLEAT_TYPES}
              />
              <EditableSpec
                label="Cleat Capacity"
                value={berth.cleatCapacity}
                field="cleatCapacity"
                patch={patch}
                selectOptions={BERTH_CLEAT_CAPACITIES}
              />
              <EditableSpec
                label="Bollard Type"
                value={berth.bollardType}
                field="bollardType"
                patch={patch}
                selectOptions={BERTH_BOLLARD_TYPES}
              />
              <EditableSpec
                label="Bollard Capacity"
                value={berth.bollardCapacity}
                field="bollardCapacity"
                patch={patch}
                selectOptions={BERTH_BOLLARD_CAPACITIES}
              />
            </CardContent>
          </Card>

          <Card>
            <CardHeader className="pb-3">
              <CardTitle className="text-sm font-medium">Tenure & Pricing</CardTitle>
            </CardHeader>
            <CardContent className="pt-0 divide-y">
              {/* Tenure type values are admin-configurable per port (Wave 5).
                  Today the list is the static union from the zod validator. */}
              <EditableSpec
                label="Tenure Type"
                value={berth.tenureType}
                field="tenureType"
                patch={patch}
                selectOptions={['permanent', 'fixed_term'] as const}
              />
              {berth.tenureType === 'fixed_term' && (
                <>
                  <SpecRow label="Years" value={berth.tenureYears} />
                  <SpecRow label="Start Date" value={berth.tenureStartDate} />
                  <SpecRow label="End Date" value={berth.tenureEndDate} />
                </>
              )}
              <EditableSpec
                label={`Price (${berth.priceCurrency || 'USD'})`}
                value={berth.price}
                displayValue={
                  berth.price
                    ? formatCurrency(berth.price, berth.priceCurrency, { maxFractionDigits: 0 })
                    : null
                }
                field="price"
                patch={patch}
                numeric
              />
            </CardContent>
          </Card>

          <BerthTagsCard berth={berth} />
        </div>
      </div>
    </div>
  );
}

export function buildBerthTabs(
  berth: BerthData,
  opts: { tenanciesModuleEnabled: boolean; maintenanceModuleEnabled: boolean } = {
    tenanciesModuleEnabled: false,
    maintenanceModuleEnabled: true,
  },
): DetailTab[] {
  const tabs: DetailTab[] = [
    {
      id: 'overview',
      label: 'Overview',
      content: <OverviewTab berth={berth} />,
    },
    {
      id: 'interests',
      label: 'Interests',
      content: <BerthInterestsTab berthId={berth.id} />,
    },
  ];
  if (opts.tenanciesModuleEnabled) {
    tabs.push({
      id: 'tenancies',
      label: 'Tenancies',
      content: <BerthTenanciesTab berthId={berth.id} />,
    });
  }
  tabs.push(...buildBerthDetailRemainder(berth, opts));
  return tabs;
}

function buildBerthDetailRemainder(
  berth: BerthData,
  opts: { maintenanceModuleEnabled: boolean } = { maintenanceModuleEnabled: true },
): DetailTab[] {
  const tabs: DetailTab[] = [
    {
      id: 'spec',
      label: 'Spec',
      content: <BerthDocumentsTab berthId={berth.id} />,
    },
    {
      id: 'deal-documents',
      label: 'Interest Documents',
      content: <BerthDealDocumentsTab berthId={berth.id} />,
    },
    {
      id: 'waiting-list',
      label: 'Waiting List',
      content: <WaitingListManager berthId={berth.id} />,
    },
  ];
  if (opts.maintenanceModuleEnabled) {
    tabs.push({
      id: 'maintenance',
      label: 'Maintenance',
      content: <BerthMaintenanceTab berthId={berth.id} />,
    });
  }
  tabs.push({
    id: 'activity',
    label: 'Activity',
    content: (
      <EntityActivityFeed
        endpoint={`/api/v1/berths/${berth.id}/activity`}
        emptyText="No activity recorded for this berth yet."
      />
    ),
  });
  return tabs;
}
