"use client";

import {
  useEffect,
  useRef,
  useState,
  type CSSProperties,
  type FormEvent,
  type PointerEvent,
  type ReactNode,
} from "react";

import {
  Badge,
  BoltIcon,
  CalendarIcon,
  ShieldIcon,
  WalletIcon,
  WrenchIcon,
} from "@/components/dashboard-ui";
import { PropertyMap } from "@/components/property-map";
import { ThemedDatePicker } from "@/components/themed-date-picker";
import type { ComplianceItem, Property } from "@/lib/property-data-uk";
import {
  daysUntil,
  formatCompactCurrency,
  formatCurrency,
  formatDate,
} from "@/lib/property-data-uk";
import { buildLocalValuation, type PropertyValuation } from "@/lib/valuation";

type CareKind = "bill" | "check";
type CareAudience = "Homeowner" | "Landlord" | "Both";
type CareStatus = "Unconfirmed" | "Booked" | "Paid" | "Complete" | "Watching";
type CareRecurrence = "One-off" | "Monthly";

type CareRecord = {
  id: string;
  propertyId: string;
  kind: CareKind;
  category: string;
  title: string;
  dueDate: string;
  amount?: number;
  provider?: string;
  reminderDays: number;
  recurrence?: CareRecurrence;
  audience: CareAudience;
  status: CareStatus;
  source: "Default" | "User";
};

type FormState = {
  propertyId: string;
  kind: CareKind;
  category: string;
  title: string;
  dueDate: string;
  amount: string;
  provider: string;
  reminderDays: string;
  recurrence: CareRecurrence;
  audience: CareAudience;
};

type PropertyCareDashboardProps = {
  properties: Property[];
  complianceItems: ComplianceItem[];
  title?: string;
  description?: string;
  headerArtwork?: ReactNode;
  showHeaderMap?: boolean;
  defaultKind?: "all" | CareKind;
  className?: string;
};

type DeadlineTone = {
  label: string;
  colour: string;
  mutedColour: string;
  textClass: string;
};

type RingModuleKey = "electric" | "gas" | "water" | "insurance" | "checks";

type RingModule = {
  key: RingModuleKey;
  label: string;
  description: string;
  icon: ReactNode;
  match: (record: CareRecord) => boolean;
};

const STORAGE_KEY = "propertypilot-home-care-records";

const BILL_CATEGORIES = [
  "Electricity",
  "Gas",
  "Water",
  "Council tax",
  "Broadband",
  "Buildings insurance",
  "Service charge",
  "Mortgage",
];

const CHECK_CATEGORIES = [
  "Certificate",
  "Boiler service",
  "Gas safety (CP12)",
  "EICR",
  "EPC",
  "Smoke and CO alarms",
  "Fire risk",
  "Legionella",
  "Licence renewal",
  "Home insurance review",
  "Other certificate",
];

const BILL_SEEDS = [
  {
    electricity: "2026-05-22",
    gas: "2026-06-03",
    water: "2026-06-08",
    councilTax: "2026-06-15",
  },
  {
    electricity: "2026-05-29",
    gas: "2026-06-11",
    water: "2026-06-19",
    councilTax: "2026-06-01",
  },
  {
    electricity: "2026-06-06",
    gas: "2026-05-25",
    water: "2026-07-05",
    councilTax: "2026-07-01",
  },
  {
    electricity: "2026-06-14",
    gas: "2026-06-21",
    water: "2026-06-27",
    councilTax: "2026-06-30",
  },
  {
    electricity: "2026-05-19",
    gas: "2026-07-03",
    water: "2026-06-12",
    councilTax: "2026-06-10",
  },
];

function cn(...classes: Array<string | false | null | undefined>) {
  return classes.filter(Boolean).join(" ");
}

function isInteractiveTarget(target: EventTarget | null) {
  return target instanceof HTMLElement
    ? Boolean(target.closest("a, button, input, label, select, textarea"))
    : false;
}

function getCategoryOptions(kind: CareKind) {
  return kind === "bill" ? BILL_CATEGORIES : CHECK_CATEGORIES;
}

function getInitialFormState(
  propertyId: string,
  preferredKind: "bill" | "check" = "bill",
): FormState {
  const kind: CareKind = preferredKind;

  return {
    propertyId,
    kind,
    category: getCategoryOptions(kind)[0],
    title: "",
    dueDate: "2026-06-01",
    amount: "",
    provider: "",
    reminderDays: "14",
    recurrence: kind === "bill" ? "Monthly" : "One-off",
    audience: "Both",
  };
}

function getRecordRecurrence(record: CareRecord): CareRecurrence {
  return record.recurrence ?? (record.kind === "bill" ? "Monthly" : "One-off");
}

function addMonthsToDate(value: string, months = 1) {
  const [year = 1970, month = 1, day = 1] = value.split("-").map(Number);
  const targetMonthIndex = month - 1 + months;
  const targetYear = year + Math.floor(targetMonthIndex / 12);
  const targetMonth = ((targetMonthIndex % 12) + 12) % 12;
  const daysInTargetMonth = new Date(
    Date.UTC(targetYear, targetMonth + 1, 0),
  ).getUTCDate();
  const targetDay = Math.min(day, daysInTargetMonth);

  return [
    targetYear.toString().padStart(4, "0"),
    (targetMonth + 1).toString().padStart(2, "0"),
    targetDay.toString().padStart(2, "0"),
  ].join("-");
}

function getNextMonthlyDueDate(value: string) {
  let nextDate = addMonthsToDate(value);
  let guard = 0;

  while (daysUntil(nextDate) <= 0 && guard < 24) {
    nextDate = addMonthsToDate(nextDate);
    guard += 1;
  }

  return nextDate;
}

function buildDefaultRecords(
  properties: Property[],
  complianceItems: ComplianceItem[],
): CareRecord[] {
  const billRecords = properties.flatMap((property, index) => {
    const seed = BILL_SEEDS[index % BILL_SEEDS.length];
    const baseAmount = Math.max(65, Math.round(property.monthlyRentRoll * 0.045));

    return [
      {
        id: `bill-${property.id}-electricity`,
        propertyId: property.id,
        kind: "bill" as const,
        category: "Electricity",
        title: "Electricity bill",
        dueDate: seed.electricity,
        amount: baseAmount,
        provider: "Energy supplier",
        reminderDays: 10,
        recurrence: "Monthly" as const,
        audience: "Both" as const,
        status: "Unconfirmed" as const,
        source: "Default" as const,
      },
      {
        id: `bill-${property.id}-gas`,
        propertyId: property.id,
        kind: "bill" as const,
        category: "Gas",
        title: "Gas or boiler cover payment",
        dueDate: seed.gas,
        amount: Math.round(baseAmount * 0.72),
        provider: "Gas supplier",
        reminderDays: 14,
        recurrence: "Monthly" as const,
        audience: "Both" as const,
        status: "Watching" as const,
        source: "Default" as const,
      },
      {
        id: `bill-${property.id}-water`,
        propertyId: property.id,
        kind: "bill" as const,
        category: "Water",
        title: "Water bill",
        dueDate: seed.water,
        amount: Math.round(baseAmount * 0.46),
        provider: "Water supplier",
        reminderDays: 12,
        recurrence: "Monthly" as const,
        audience: "Both" as const,
        status: "Unconfirmed" as const,
        source: "Default" as const,
      },
      {
        id: `bill-${property.id}-council-tax`,
        propertyId: property.id,
        kind: "bill" as const,
        category: "Council tax",
        title: "Council tax or local bill",
        dueDate: seed.councilTax,
        amount: 178 + (index % 4) * 22,
        provider: property.localAuthority,
        reminderDays: 7,
        recurrence: "Monthly" as const,
        audience: "Homeowner" as const,
        status: "Unconfirmed" as const,
        source: "Default" as const,
      },
    ];
  });

  const complianceRecords = complianceItems.map((item) => ({
    id: `check-${item.id}`,
    propertyId: item.propertyId,
    kind: "check" as const,
    category: item.type,
    title: item.title,
    dueDate: item.dueDate,
    provider: item.owner,
    reminderDays: 30,
    recurrence: "One-off" as const,
    audience: "Landlord" as const,
    status: item.status === "Completed" ? ("Complete" as const) : ("Booked" as const),
    source: "Default" as const,
  }));

  return [...billRecords, ...complianceRecords];
}

function isCareRecord(value: unknown): value is CareRecord {
  if (!value || typeof value !== "object" || Array.isArray(value)) {
    return false;
  }

  const record = value as Partial<CareRecord>;

  return (
    typeof record.id === "string" &&
    typeof record.propertyId === "string" &&
    (record.kind === "bill" || record.kind === "check") &&
    typeof record.category === "string" &&
    typeof record.title === "string" &&
    typeof record.dueDate === "string" &&
    typeof record.reminderDays === "number" &&
    (record.recurrence === undefined ||
      record.recurrence === "One-off" ||
      record.recurrence === "Monthly") &&
    (record.audience === "Homeowner" ||
      record.audience === "Landlord" ||
      record.audience === "Both") &&
    (record.status === "Unconfirmed" ||
      record.status === "Booked" ||
      record.status === "Paid" ||
      record.status === "Complete" ||
      record.status === "Watching") &&
    (record.source === "Default" || record.source === "User")
  );
}

function loadStoredRecords(defaultRecords: CareRecord[]) {
  try {
    const stored = window.localStorage.getItem(STORAGE_KEY);

    if (!stored) {
      return defaultRecords;
    }

    const parsed: unknown = JSON.parse(stored);

    if (!Array.isArray(parsed)) {
      return defaultRecords;
    }

    const records = parsed.filter(isCareRecord);

    if (records.length === 0) {
      return defaultRecords;
    }

    const missingWaterDefaults = defaultRecords.filter(
      (record) =>
        record.category === "Water" &&
        !records.some(
          (storedRecord) =>
            storedRecord.propertyId === record.propertyId &&
            storedRecord.category === record.category,
        ),
    );

    return [...records, ...missingWaterDefaults];
  } catch {
    window.localStorage.removeItem(STORAGE_KEY);
    return defaultRecords;
  }
}

function getDeadlineTone(record?: CareRecord): DeadlineTone {
  if (!record) {
    return {
      label: "Add date",
      colour: "#7a8581",
      mutedColour: "rgba(122,133,129,0.22)",
      textClass: "text-white/62",
    };
  }

  if (record.status === "Paid" || record.status === "Complete") {
    return {
      label: record.status,
      colour: "#a9c65c",
      mutedColour: "rgba(169,198,92,0.22)",
      textClass: "text-[#c8f06e]",
    };
  }

  const days = daysUntil(record.dueDate);

  if (days < 0) {
    return {
      label: "Overdue",
      colour: "#ff754f",
      mutedColour: "rgba(255,117,79,0.18)",
      textClass: "text-[#ff9a7d]",
    };
  }

  if (days <= record.reminderDays) {
    return {
      label: `${days} days`,
      colour: "#ff9a35",
      mutedColour: "rgba(255,154,53,0.2)",
      textClass: "text-[#ffb15f]",
    };
  }

  if (days <= 60) {
    return {
      label: `${days} days`,
      colour: "#c8d66a",
      mutedColour: "rgba(200,214,106,0.18)",
      textClass: "text-[#dbe984]",
    };
  }

  return {
    label: `${days} days`,
    colour: "#e9eee7",
    mutedColour: "rgba(233,238,231,0.12)",
    textClass: "text-white/78",
  };
}

function sortByUrgency(records: CareRecord[]) {
  return records
    .slice()
    .sort((a, b) => daysUntil(a.dueDate) - daysUntil(b.dueDate));
}

function getTimeframeProgress(record?: CareRecord) {
  if (!record) {
    return 6;
  }

  if (record.status === "Paid" || record.status === "Complete") {
    return 100;
  }

  const days = daysUntil(record.dueDate);

  if (days <= 0) {
    return 6;
  }

  return Math.max(10, Math.min(100, (days / 120) * 100));
}

function getDaysLabel(record: CareRecord) {
  const days = daysUntil(record.dueDate);

  if (record.status === "Paid" || record.status === "Complete") {
    return record.kind === "bill" ? "Paid" : "Complete";
  }

  if (days < 0) {
    return `${Math.abs(days)} days overdue`;
  }

  if (days === 0) {
    return "Due today";
  }

  return `Due in ${days} days`;
}

function isUtilityModule(module: RingModule) {
  return (
    module.key === "electric" || module.key === "gas" || module.key === "water"
  );
}

function getPropertyName(properties: Property[], propertyId: string) {
  return properties.find((property) => property.id === propertyId)?.name ?? propertyId;
}

function findModuleRecord(
  records: CareRecord[],
  propertyId: string,
  module: RingModule,
) {
  return sortByUrgency(
    records.filter(
      (record) =>
        record.propertyId === propertyId &&
        record.status !== "Paid" &&
        record.status !== "Complete" &&
        module.match(record),
    ),
  )[0];
}

function CareIconTile({
  module,
  record,
  isDateEditorOpen = false,
  onClick,
  onDateChange,
}: {
  module: RingModule;
  record?: CareRecord;
  isDateEditorOpen?: boolean;
  onClick: () => void;
  onDateChange?: (recordId: string, dueDate: string) => void;
}) {
  const tone = getDeadlineTone(record);
  const progress = getTimeframeProgress(record);
  const barStyle = {
    backgroundColor: tone.colour,
    width: `${progress}%`,
  } as CSSProperties;
  const canEditDate = Boolean(
    record && record.kind === "bill" && onDateChange && isUtilityModule(module),
  );
  const timeframeLabel = record ? getDaysLabel(record) : "Add timeframe";
  const dateLabel = record
    ? `${formatDate(record.dueDate)}${
        getRecordRecurrence(record) === "Monthly" ? " - monthly" : ""
      }`
    : "No date set";
  const isUrgent =
    record &&
    (daysUntil(record.dueDate) <= record.reminderDays || daysUntil(record.dueDate) < 0);

  return (
    <div className="group flex min-w-0 flex-col gap-3">
      <button
        aria-expanded={canEditDate ? isDateEditorOpen : undefined}
        className="care-dark-card flex min-h-[152px] min-w-0 flex-col rounded-[24px] border border-white/10 p-3 text-left transition hover:-translate-y-0.5 hover:border-[#c8f06e]/45 hover:bg-white/[0.08]"
        onClick={onClick}
        type="button"
      >
        <span className="flex items-start justify-between gap-3">
          <span className="care-icon-core relative grid h-12 w-12 shrink-0 place-items-center rounded-2xl border border-white/10 text-white shadow-[inset_0_1px_0_rgba(255,255,255,0.08)]">
            {module.icon}
            {isUrgent ? (
              <span className="absolute -right-1 -top-1 grid h-5 w-5 place-items-center rounded-full bg-[#ff9a35] text-[10px] font-black text-white shadow-lg">
                !
              </span>
            ) : null}
          </span>
          <span className="min-w-0 text-right">
            <span className="block text-[10px] font-semibold uppercase tracking-[0.16em] text-white/45">
              {module.label}
            </span>
            <span className={cn("mt-1 block text-xs font-semibold", tone.textClass)}>
              {record ? tone.label : module.description}
            </span>
          </span>
        </span>

        <span className="mt-4 block min-w-0">
          <span className="block truncate text-xs font-medium text-white/72">
            {timeframeLabel}
          </span>
          <span className="mt-1 block truncate text-[11px] text-white/42">
            {dateLabel}
          </span>
        </span>

        <span
          aria-hidden="true"
          className="mt-auto block h-2 overflow-hidden rounded-full"
          style={{ backgroundColor: tone.mutedColour }}
        >
          <span
            className="block h-full rounded-full transition-[width] duration-300"
            style={barStyle}
          />
        </span>
      </button>

      {canEditDate && record && onDateChange && isDateEditorOpen ? (
        <div className="w-full max-w-[11rem] rounded-[20px] border border-white/12 bg-white/[0.07] p-2 shadow-[0_16px_36px_rgba(0,0,0,0.16)]">
          <ThemedDatePicker
            buttonClassName="mt-1 justify-center rounded-full border-white/12 px-3 py-2 text-center text-xs font-bold"
            label={`Change ${module.label} date`}
            labelClassName="text-center text-[10px] font-semibold uppercase tracking-[0.14em] text-white/45"
            onChange={(nextDate) => onDateChange(record.id, nextDate)}
            tone="dark"
            value={record.dueDate}
          />
        </div>
      ) : null}
    </div>
  );
}

function RecordRow({
  record,
  properties,
  onRemove,
  onDateChange,
  onStatusChange,
}: {
  record: CareRecord;
  properties: Property[];
  onRemove: (id: string) => void;
  onDateChange: (id: string, dueDate: string) => void;
  onStatusChange: (id: string, status: CareStatus) => void;
}) {
  const tone = getDeadlineTone(record);
  const completeStatus = record.kind === "bill" ? "Paid" : "Complete";
  const recurrence = getRecordRecurrence(record);
  const completeLabel =
    recurrence === "Monthly"
      ? record.kind === "bill"
        ? "Paid + reset"
        : "Done + reset"
      : completeStatus;

  return (
    <article className="relative rounded-[22px] border border-white/10 bg-white/[0.055] p-4 pt-10">
      <ThemedDatePicker
        ariaLabel={`Change ${record.title} date`}
        buttonClassName="care-date-link"
        className="absolute right-4 top-3 z-20 w-[17rem] max-w-[calc(100%-2rem)]"
        onChange={(nextDate) => onDateChange(record.id, nextDate)}
        tone="light"
        value={record.dueDate}
      />
      <div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
        <div className="min-w-0">
          <div className="flex flex-wrap items-center gap-2">
            <span
              className="rounded-full border px-2.5 py-1 text-[11px] font-black uppercase tracking-[0.18em]"
              style={{
                backgroundColor: "#f6f8f2",
                borderColor: tone.colour,
                color: "#123238",
              }}
            >
              {record.category}
            </span>
            <span className="text-xs uppercase tracking-[0.18em] text-white/45">
              {record.audience}
            </span>
            <span className="rounded-full border border-white/70 bg-[#f6f8f2] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em] text-[#1e2723]">
              {recurrence}
            </span>
          </div>
          <h3 className="mt-2 text-base font-semibold text-white">{record.title}</h3>
          <p className="mt-1 text-sm leading-6 text-white/58">
            {getPropertyName(properties, record.propertyId)}
            {record.amount ? ` - ${formatCurrency(record.amount)}` : ""}
            {record.provider ? ` - ${record.provider}` : ""}
          </p>
        </div>
        <div className="flex flex-wrap items-center gap-2">
          <span className={cn("text-sm font-semibold", tone.textClass)}>
            {getDaysLabel(record)}
          </span>
          <button
            className="rounded-full border border-white/12 px-3 py-2 text-xs font-bold uppercase tracking-[0.14em] text-white/72 transition hover:border-[#c8f06e]/40 hover:text-[#c8f06e]"
            onClick={() => onStatusChange(record.id, completeStatus)}
            type="button"
          >
            {completeLabel}
          </button>
          <button
            className="rounded-full border border-white/12 px-3 py-2 text-xs font-bold uppercase tracking-[0.14em] text-white/50 transition hover:border-[#ff9a7d]/40 hover:text-[#ff9a7d]"
            onClick={() => onRemove(record.id)}
            type="button"
          >
            Remove
          </button>
        </div>
      </div>
    </article>
  );
}

function PropertyArrowIcon({ direction }: { direction: "previous" | "next" }) {
  return (
    <svg
      aria-hidden="true"
      className="h-5 w-5"
      fill="none"
      viewBox="0 0 24 24"
    >
      <path
        d={direction === "previous" ? "m15 18-6-6 6-6" : "m9 6 6 6-6 6"}
        stroke="currentColor"
        strokeLinecap="round"
        strokeLinejoin="round"
        strokeWidth="2.2"
      />
    </svg>
  );
}

function WaterDropIcon() {
  return (
    <svg
      aria-hidden="true"
      className="h-9 w-9"
      fill="none"
      viewBox="0 0 24 24"
    >
      <path
        d="M12 3.5c3.9 4.6 6 8.1 6 11.1a6 6 0 0 1-12 0c0-3 2.1-6.5 6-11.1Z"
        stroke="currentColor"
        strokeLinejoin="round"
        strokeWidth="1.9"
      />
      <path
        d="M9.2 15.2c.4 1.5 1.5 2.4 3.2 2.5"
        stroke="currentColor"
        strokeLinecap="round"
        strokeWidth="1.9"
      />
    </svg>
  );
}

export function PropertyCareDashboard({
  properties,
  complianceItems,
  title = "Home care cockpit",
  description = "Track bills, electric reminders, home insurance, and compliance dates in the same simple view whether you live there, let it out, or do both.",
  headerArtwork,
  showHeaderMap = false,
  defaultKind = "all",
  className,
}: PropertyCareDashboardProps) {
  const [records, setRecords] = useState<CareRecord[]>(() =>
    buildDefaultRecords(properties, complianceItems),
  );
  const [activeIndex, setActiveIndex] = useState(0);
  const [isFormOpen, setIsFormOpen] = useState(false);
  const [editingDateRecordId, setEditingDateRecordId] = useState<string | null>(null);
  const [filterKind, setFilterKind] = useState<"all" | CareKind>(defaultKind);
  const dragStartX = useRef<number | null>(null);
  const dragStartY = useRef<number | null>(null);
  const dragStartedOnInteractive = useRef(false);
  const activeProperty = properties[activeIndex] ?? properties[0];
  const [valuation, setValuation] = useState<PropertyValuation | null>(null);
  const [valuationLoading, setValuationLoading] = useState(false);
  const [formState, setFormState] = useState<FormState>(
    getInitialFormState(
      activeProperty?.id ?? "",
      defaultKind === "check" ? "check" : "bill",
    ),
  );

  useEffect(() => {
    if (!activeProperty) {
      return;
    }

    const controller = new AbortController();

    async function loadValuation() {
      setValuationLoading(true);

      try {
        const response = await fetch(`/api/zoopla/valuation/${activeProperty.slug}`, {
          signal: controller.signal,
        });

        if (!response.ok) {
          setValuation(buildLocalValuation(activeProperty));
          return;
        }

        setValuation((await response.json()) as PropertyValuation);
      } catch {
        if (!controller.signal.aborted) {
          setValuation(buildLocalValuation(activeProperty));
        }
      } finally {
        if (!controller.signal.aborted) {
          setValuationLoading(false);
        }
      }
    }

    setValuation(null);
    loadValuation();

    return () => controller.abort();
  }, [activeProperty]);

  useEffect(() => {
    const frame = window.requestAnimationFrame(() => {
      setRecords(loadStoredRecords(buildDefaultRecords(properties, complianceItems)));
    });

    return () => window.cancelAnimationFrame(frame);
  }, [complianceItems, properties]);

  if (!activeProperty) {
    return null;
  }

  const ringModules: RingModule[] = [
    {
      key: "electric",
      label: "Electric",
      description: "Add bill",
      icon: <BoltIcon className="h-9 w-9" />,
      match: (record) =>
        record.kind === "bill" && record.category.toLowerCase().includes("electric"),
    },
    {
      key: "gas",
      label: "Gas",
      description: "Add date",
      icon: <WrenchIcon className="h-9 w-9" />,
      match: (record) =>
        record.kind === "bill" &&
        (record.category.toLowerCase().includes("gas") ||
          record.category.toLowerCase().includes("boiler")),
    },
    {
      key: "water",
      label: "Water",
      description: "Add bill",
      icon: <WaterDropIcon />,
      match: (record) =>
        record.kind === "bill" && record.category.toLowerCase().includes("water"),
    },
    {
      key: "insurance",
      label: "Insure",
      description: "Add policy",
      icon: <ShieldIcon className="h-9 w-9" />,
      match: (record) => record.category.toLowerCase().includes("insurance"),
    },
    {
      key: "checks",
      label: "Checks",
      description: "Add check",
      icon: <CalendarIcon className="h-9 w-9" />,
      match: (record) => record.kind === "check",
    },
  ];

  const activeRecords = sortByUrgency(
    records.filter((record) => record.propertyId === activeProperty.id),
  );
  const visibleRecords = activeRecords.filter((record) => {
    if (filterKind === "all") {
      return true;
    }

    return record.kind === filterKind;
  });
  const urgentRecord = activeRecords.find(
    (record) => record.status !== "Paid" && record.status !== "Complete",
  );
  const overdueCount = records.filter(
    (record) =>
      record.status !== "Paid" &&
      record.status !== "Complete" &&
      daysUntil(record.dueDate) < 0,
  ).length;
  const soonCount = records.filter(
    (record) =>
      record.status !== "Paid" &&
      record.status !== "Complete" &&
      daysUntil(record.dueDate) >= 0 &&
      daysUntil(record.dueDate) <= record.reminderDays,
  ).length;

  function persistRecords(nextRecords: CareRecord[]) {
    setRecords(nextRecords);
    window.localStorage.setItem(STORAGE_KEY, JSON.stringify(nextRecords));
  }

  function showProperty(index: number) {
    const nextProperty = properties[index];

    if (!nextProperty) {
      return;
    }

    setActiveIndex(index);
    setEditingDateRecordId(null);
    setFormState((current) => ({
      ...current,
      propertyId: nextProperty.id,
    }));
  }

  function showAdjacentProperty(direction: -1 | 1) {
    const nextIndex = (activeIndex + direction + properties.length) % properties.length;
    showProperty(nextIndex);
  }

  function handleSlideStart(event: PointerEvent<HTMLElement>) {
    if (event.pointerType === "mouse" && event.button !== 0) {
      return;
    }

    dragStartedOnInteractive.current = isInteractiveTarget(event.target);
    dragStartX.current = event.clientX;
    dragStartY.current = event.clientY;
  }

  function clearSlideState() {
    dragStartX.current = null;
    dragStartY.current = null;
    dragStartedOnInteractive.current = false;
  }

  function handleSlideEnd(event: PointerEvent<HTMLElement>) {
    if (
      dragStartX.current === null ||
      dragStartY.current === null ||
      dragStartedOnInteractive.current
    ) {
      clearSlideState();
      return;
    }

    const deltaX = event.clientX - dragStartX.current;
    const deltaY = event.clientY - dragStartY.current;
    const isHorizontalSwipe =
      Math.abs(deltaX) > 54 && Math.abs(deltaX) > Math.abs(deltaY) * 1.25;

    clearSlideState();

    if (!isHorizontalSwipe) {
      return;
    }

    if (deltaX < 0) {
      showAdjacentProperty(1);
    } else {
      showAdjacentProperty(-1);
    }
  }

  function handleAddRecord(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();

    const title = formState.title.trim() || formState.category;
    const amountValue = Number(formState.amount);
    const reminderDays = Number(formState.reminderDays);

    const newRecord: CareRecord = {
      id: `user-${Date.now()}`,
      propertyId: formState.propertyId,
      kind: formState.kind,
      category: formState.category,
      title,
      dueDate: formState.dueDate,
      amount: Number.isFinite(amountValue) && amountValue > 0 ? amountValue : undefined,
      provider: formState.provider.trim() || undefined,
      reminderDays:
        Number.isFinite(reminderDays) && reminderDays >= 0 ? reminderDays : 14,
      recurrence: formState.recurrence,
      audience: formState.audience,
      status: "Unconfirmed",
      source: "User",
    };

    persistRecords([newRecord, ...records]);
    setFormState({
      ...getInitialFormState(formState.propertyId, formState.kind),
      kind: formState.kind,
      category: formState.category,
      recurrence: formState.recurrence,
      audience: formState.audience,
    });
  }

  function handleRemoveRecord(id: string) {
    persistRecords(records.filter((record) => record.id !== id));
  }

  function handleStatusChange(id: string, status: CareStatus) {
    persistRecords(
      records.map((record) => {
        if (record.id !== id) {
          return record;
        }

        if (
          (status === "Paid" || status === "Complete") &&
          getRecordRecurrence(record) === "Monthly"
        ) {
          return {
            ...record,
            dueDate: getNextMonthlyDueDate(record.dueDate),
            status: "Unconfirmed" as const,
            source: "User" as const,
          };
        }

        return { ...record, status };
      }),
    );
  }

  function handleRecordDateChange(id: string, dueDate: string) {
    if (!dueDate) {
      return;
    }

    persistRecords(
      records.map((record) =>
        record.id === id ? { ...record, dueDate, source: "User" } : record,
      ),
    );
    setEditingDateRecordId(null);
  }

  function prepareModuleInput(module: RingModule) {
    const kind: CareKind = module.key === "checks" ? "check" : "bill";
    const category =
      module.key === "electric"
        ? "Electricity"
        : module.key === "gas"
          ? "Gas"
          : module.key === "water"
            ? "Water"
            : module.key === "insurance"
              ? "Buildings insurance"
              : "Smoke and CO alarms";

    setFilterKind(kind);
    setFormState((current) => ({
      ...current,
      propertyId: activeProperty.id,
      kind,
      category,
      title: "",
      recurrence: kind === "bill" ? "Monthly" : "One-off",
    }));
    setIsFormOpen(true);
  }

  function handleModuleClick(module: RingModule, record?: CareRecord) {
    if (record?.kind === "bill" && isUtilityModule(module)) {
      setIsFormOpen(false);
      setEditingDateRecordId((current) => (current === record.id ? null : record.id));
      return;
    }

    setEditingDateRecordId(null);
    prepareModuleInput(module);
  }

  return (
    <section
      className={cn(
        "care-cockpit relative overflow-hidden rounded-[34px] p-5 text-white md:p-7",
        className,
      )}
      onPointerCancel={clearSlideState}
      onPointerDown={handleSlideStart}
      onPointerUp={handleSlideEnd}
    >
      <div className="care-ambient-green pointer-events-none absolute -right-16 top-8 h-52 w-52 rounded-full bg-[#c8f06e]/16 blur-3xl" />
      <div className="care-ambient-blue pointer-events-none absolute left-8 top-28 h-40 w-40 rounded-full bg-[#38556b]/50 blur-3xl" />
      <button
        aria-label={`Show previous property before ${activeProperty.name}`}
        className="absolute left-2 top-56 z-20 grid h-11 w-11 -translate-y-1/2 place-items-center rounded-full border border-white/14 bg-white/[0.08] text-white shadow-[0_16px_36px_rgba(0,0,0,0.18)] transition hover:border-[#c8f06e]/50 hover:bg-[#c8f06e] hover:text-[#0d2029] focus:outline-none focus:ring-4 focus:ring-[#c8f06e]/20 sm:top-60 md:h-12 md:w-12"
        onClick={() => showAdjacentProperty(-1)}
        type="button"
      >
        <PropertyArrowIcon direction="previous" />
      </button>
      <button
        aria-label={`Show next property after ${activeProperty.name}`}
        className="absolute right-2 top-56 z-20 grid h-11 w-11 -translate-y-1/2 place-items-center rounded-full border border-white/14 bg-white/[0.08] text-white shadow-[0_16px_36px_rgba(0,0,0,0.18)] transition hover:border-[#c8f06e]/50 hover:bg-[#c8f06e] hover:text-[#0d2029] focus:outline-none focus:ring-4 focus:ring-[#c8f06e]/20 sm:top-60 md:h-12 md:w-12"
        onClick={() => showAdjacentProperty(1)}
        type="button"
      >
        <PropertyArrowIcon direction="next" />
      </button>

      <div className="relative z-10 cursor-grab select-none touch-pan-y px-10 active:cursor-grabbing sm:px-12">
        <div className="flex flex-col gap-5 lg:flex-row lg:items-start lg:justify-between">
          <div className="min-w-0">
            <p className="font-mono text-xs uppercase tracking-[0.34em] text-[#c8f06e]">
              PropertyPilot home care
            </p>
            <h2 className="mt-3 text-3xl font-black tracking-tight text-white md:text-5xl">
              {activeProperty.postcode}
            </h2>
            <p className="mt-1 text-2xl font-bold text-white">{activeProperty.name}</p>
            <p className="mt-1 text-lg font-semibold text-white/42">
              {activeProperty.type} - {activeProperty.city}
            </p>
          </div>

          <div className="max-w-xl space-y-3 lg:text-right">
            <div className="flex flex-wrap gap-2 lg:justify-end">
              <Badge tone="success">{properties.length} homes</Badge>
              <Badge tone={overdueCount > 0 ? "red" : "teal"}>
                {overdueCount} overdue
              </Badge>
              <Badge tone={soonCount > 0 ? "amber" : "neutral"}>
                {soonCount} reminders
              </Badge>
            </div>
            {showHeaderMap ? (
              <div className="w-full max-w-[24rem] rounded-[28px] border border-white/12 bg-white/[0.07] p-3 shadow-[0_22px_55px_rgba(0,0,0,0.16)]">
                <PropertyMap
                  lat={activeProperty.coordinates.lat}
                  lng={activeProperty.coordinates.lng}
                  title={activeProperty.name}
                />
              </div>
            ) : headerArtwork ? (
              <div className="flex justify-start lg:justify-end">{headerArtwork}</div>
            ) : (
              <>
                <h3 className="text-xl font-semibold text-white">{title}</h3>
                <p className="text-sm leading-6 text-white/58">{description}</p>
              </>
            )}
          </div>
        </div>

        <div className="mt-7 flex justify-end">
          <button
            aria-label="Add bill or check"
            className="care-plus-button grid h-11 w-11 place-items-center rounded-full text-3xl font-light leading-none transition hover:bg-[#c8f06e]"
            onClick={() => {
              setFormState((current) => ({
                ...current,
                propertyId: activeProperty.id,
              }));
              setIsFormOpen((current) => !current);
            }}
            type="button"
          >
            +
          </button>
        </div>

        <div className="mt-7 grid grid-cols-2 gap-5 md:grid-cols-3 xl:grid-cols-5">
          {ringModules.map((module) => {
            const moduleRecord = findModuleRecord(records, activeProperty.id, module);

            return (
              <CareIconTile
                isDateEditorOpen={moduleRecord?.id === editingDateRecordId}
                key={module.key}
                module={module}
                onClick={() => handleModuleClick(module, moduleRecord)}
                onDateChange={handleRecordDateChange}
                record={moduleRecord}
              />
            );
          })}
        </div>

        <div className="care-dark-card mt-7 rounded-[24px] border border-white/12 p-5">
          <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
            <div>
              <p className="font-mono text-xs uppercase tracking-[0.26em] text-[#c8f06e]">
                Zoopla valuation
              </p>
              <p className="mt-2 text-3xl font-black tracking-tight text-white">
                {valuationLoading || !valuation
                  ? "Loading valuation"
                  : formatCurrency(valuation.estimate)}
              </p>
            </div>
            <span className="w-fit rounded-full border border-white/12 bg-white/[0.07] px-3 py-1.5 font-mono text-[11px] font-black uppercase tracking-[0.2em] text-white/66">
              {valuation?.connected
                ? "Zoopla API live"
                : valuation
                  ? "Connect Zoopla"
                  : "Checking"}
            </span>
          </div>

          {valuation ? (
            <>
              <dl className="mt-5 grid gap-3 text-sm text-white/58 sm:grid-cols-3">
                <div className="rounded-[18px] border border-white/10 bg-white/[0.055] p-4">
                  <dt>Estimate range</dt>
                  <dd className="mt-1 font-black text-white">
                    {formatCompactCurrency(valuation.lowEstimate)} -{" "}
                    {formatCompactCurrency(valuation.highEstimate)}
                  </dd>
                </div>
                <div className="rounded-[18px] border border-white/10 bg-white/[0.055] p-4">
                  <dt>Rent estimate</dt>
                  <dd className="mt-1 font-black text-white">
                    {formatCompactCurrency(valuation.rentalEstimate)} / mo
                  </dd>
                </div>
                <div className="rounded-[18px] border border-white/10 bg-white/[0.055] p-4">
                  <dt>Confidence</dt>
                  <dd className="mt-1 font-black text-white">
                    {valuation.confidence}
                  </dd>
                </div>
              </dl>
              <p className="mt-4 text-sm leading-6 text-white/58">{valuation.note}</p>
            </>
          ) : (
            <p className="mt-4 text-sm text-white/58">
              Checking the valuation route for {activeProperty.name}.
            </p>
          )}
        </div>

        <div className="mt-7 grid gap-4 xl:grid-cols-[1fr_0.82fr]">
          <div className="space-y-4">
            <button
              className="flex w-full items-center justify-between gap-4 rounded-[18px] border border-white/16 bg-white/[0.065] px-5 py-4 text-left transition hover:border-[#c8f06e]/38"
              onClick={() => {
                if (urgentRecord) {
                  setFilterKind(urgentRecord.kind);
                }

                setIsFormOpen(true);
              }}
              type="button"
            >
              <span className="flex min-w-0 items-center gap-4">
                <span className="grid h-11 w-11 shrink-0 place-items-center rounded-full border border-[#ff9a35]/60 text-[#ff9a35]">
                  {urgentRecord?.kind === "bill" ? (
                    <WalletIcon className="h-5 w-5" />
                  ) : (
                    <ShieldIcon className="h-5 w-5" />
                  )}
                </span>
                <span>
                  <span className="block text-sm font-medium text-white">
                    {urgentRecord
                      ? `Confirm ${urgentRecord.category.toLowerCase()} for ${activeProperty.name}`
                      : `Add first bill or check for ${activeProperty.name}`}
                  </span>
                  <span className="mt-1 block text-xs leading-5 text-white/55">
                    {urgentRecord
                      ? `${formatDate(urgentRecord.dueDate)} - ${getDaysLabel(
                          urgentRecord,
                        )}`
                      : "Use the plus button to save your own home reminder."}
                  </span>
                </span>
              </span>
              <span className="text-4xl font-light text-white/70">&gt;</span>
            </button>

            <div className="care-dark-card rounded-[18px] border border-white/10 px-5 py-4">
              <p className="text-base font-semibold text-[#c8f06e]">
                Works for homeowners and landlords
              </p>
              <p className="mt-1 text-xs leading-5 text-white/66">
                Add personal home bills, owner-occupier insurance, mortgage dates,
                landlord certificates, tenant-safety checks, or anything else that needs
                a reminder.
              </p>
            </div>
          </div>

          <div className="grid grid-cols-2 gap-4">
            {[
              ["Electricity", "Meter readings, tariff renewals, smart meter notes"],
              ["Council tax", "Owner bills, void periods, exemptions"],
              ["Insurance", "Buildings, contents, landlord policies"],
              ["Compliance", "CP12, EICR, EPC, fire, licence, alarms"],
            ].map(([label, detail]) => (
              <div
                className="rounded-[18px] border border-white/10 bg-white/[0.052] p-4"
                key={label}
              >
                <div className="mx-auto grid h-14 w-14 place-items-center rounded-full border border-white/18 text-white/80">
                  {label === "Electricity" ? (
                    <BoltIcon />
                  ) : label === "Insurance" ? (
                    <ShieldIcon />
                  ) : label === "Council tax" ? (
                    <WalletIcon />
                  ) : (
                    <CalendarIcon />
                  )}
                </div>
                <p className="mt-3 text-center text-xs font-semibold text-white">
                  {label}
                </p>
                <p className="mt-2 text-center text-[11px] leading-5 text-white/48">
                  {detail}
                </p>
              </div>
            ))}
          </div>
        </div>

        {isFormOpen ? (
          <form
            className="care-form-panel mt-6 rounded-[24px] border border-[#c8f06e]/20 p-5"
            onSubmit={handleAddRecord}
          >
            <div className="mb-4 flex flex-col gap-2 md:flex-row md:items-end md:justify-between">
              <div>
                <p className="font-mono text-[10px] uppercase tracking-[0.22em] text-[#c8f06e]">
                  Add your own data
                </p>
                <h3 className="mt-2 text-lg font-semibold text-white">
                  Save a bill, certificate, or homeowner reminder
                </h3>
              </div>
              <button
                className="rounded-full border border-white/12 px-3.5 py-1.5 text-xs font-medium text-white/65 transition hover:border-white/30 hover:text-white"
                onClick={() => setIsFormOpen(false)}
                type="button"
              >
                Close
              </button>
            </div>

            <div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
              <label className="space-y-1.5 text-xs font-medium text-white/70">
                Property or home
                <select
                  className="care-field w-full rounded-2xl border border-white/12 px-4 py-3 text-sm text-white outline-none focus:border-[#c8f06e]/60"
                  onChange={(event) =>
                    setFormState((current) => ({
                      ...current,
                      propertyId: event.currentTarget.value,
                    }))
                  }
                  value={formState.propertyId}
                >
                  {properties.map((property) => (
                    <option key={property.id} value={property.id}>
                      {property.name}
                    </option>
                  ))}
                </select>
              </label>

              <label className="space-y-1.5 text-xs font-medium text-white/70">
                Type
                <select
                  className="care-field w-full rounded-2xl border border-white/12 px-4 py-3 text-sm text-white outline-none focus:border-[#c8f06e]/60"
                  onChange={(event) => {
                    const kind = event.currentTarget.value as CareKind;

                    setFormState((current) => ({
                      ...current,
                      kind,
                      category: getCategoryOptions(kind)[0],
                      recurrence: kind === "bill" ? "Monthly" : "One-off",
                    }));
                    setFilterKind(kind);
                  }}
                  value={formState.kind}
                >
                  <option value="bill">Bill or payment</option>
                  <option value="check">Compliance or safety check</option>
                </select>
              </label>

              <label className="space-y-1.5 text-xs font-medium text-white/70">
                Category
                <select
                  className="care-field w-full rounded-2xl border border-white/12 px-4 py-3 text-sm text-white outline-none focus:border-[#c8f06e]/60"
                  onChange={(event) =>
                    setFormState((current) => ({
                      ...current,
                      category: event.currentTarget.value,
                    }))
                  }
                  value={formState.category}
                >
                  {getCategoryOptions(formState.kind).map((category) => (
                    <option key={category} value={category}>
                      {category}
                    </option>
                  ))}
                </select>
              </label>

              <label className="space-y-1.5 text-xs font-medium text-white/70">
                For
                <select
                  className="care-field w-full rounded-2xl border border-white/12 px-4 py-3 text-sm text-white outline-none focus:border-[#c8f06e]/60"
                  onChange={(event) =>
                    setFormState((current) => ({
                      ...current,
                      audience: event.currentTarget.value as CareAudience,
                    }))
                  }
                  value={formState.audience}
                >
                  <option value="Both">Homeowner and landlord</option>
                  <option value="Homeowner">Homeowner</option>
                  <option value="Landlord">Landlord</option>
                </select>
              </label>

              <label className="space-y-1.5 text-xs font-medium text-white/70 xl:col-span-2">
                Reminder name
                <input
                  className="care-field w-full rounded-2xl border border-white/12 px-4 py-3 text-sm text-white outline-none placeholder:text-white/28 focus:border-[#c8f06e]/60"
                  onChange={(event) =>
                    setFormState((current) => ({
                      ...current,
                      title: event.currentTarget.value,
                    }))
                  }
                  placeholder="e.g. E.ON electricity bill, EICR certificate, CP12"
                  value={formState.title}
                />
              </label>

              <ThemedDatePicker
                buttonClassName="mt-1.5 rounded-2xl border-white/12 px-4 py-3 text-sm"
                label={formState.kind === "check" ? "Certificate or expiry date" : "Due date"}
                labelClassName="text-xs font-medium text-white/70"
                onChange={(nextDate) =>
                  setFormState((current) => ({
                    ...current,
                    dueDate: nextDate,
                  }))
                }
                required
                tone="dark"
                value={formState.dueDate}
              />

              <label className="space-y-1.5 text-xs font-medium text-white/70">
                Amount
                <input
                  className="care-field w-full rounded-2xl border border-white/12 px-4 py-3 text-sm text-white outline-none placeholder:text-white/28 focus:border-[#c8f06e]/60"
                  min="0"
                  onChange={(event) =>
                    setFormState((current) => ({
                      ...current,
                      amount: event.currentTarget.value,
                    }))
                  }
                  placeholder="Optional"
                  type="number"
                  value={formState.amount}
                />
              </label>

              <label className="space-y-1.5 text-xs font-medium text-white/70 xl:col-span-2">
                Supplier, contractor, certificate ref, or note
                <input
                  className="care-field w-full rounded-2xl border border-white/12 px-4 py-3 text-sm text-white outline-none placeholder:text-white/28 focus:border-[#c8f06e]/60"
                  onChange={(event) =>
                    setFormState((current) => ({
                      ...current,
                      provider: event.currentTarget.value,
                    }))
                  }
                  placeholder="e.g. Octopus Energy, Gas Safe engineer, certificate ref"
                  value={formState.provider}
                />
              </label>

              <label className="space-y-1.5 text-xs font-medium text-white/70">
                Remind me
                <select
                  className="care-field w-full rounded-2xl border border-white/12 px-4 py-3 text-sm text-white outline-none focus:border-[#c8f06e]/60"
                  onChange={(event) =>
                    setFormState((current) => ({
                      ...current,
                      reminderDays: event.currentTarget.value,
                    }))
                  }
                  value={formState.reminderDays}
                >
                  <option value="3">3 days before</option>
                  <option value="7">7 days before</option>
                  <option value="14">14 days before</option>
                  <option value="30">30 days before</option>
                  <option value="60">60 days before</option>
                </select>
              </label>

              <label className="space-y-1.5 text-xs font-medium text-white/70">
                Repeat
                <select
                  className="care-field w-full rounded-2xl border border-white/12 px-4 py-3 text-sm text-white outline-none focus:border-[#c8f06e]/60"
                  onChange={(event) =>
                    setFormState((current) => ({
                      ...current,
                      recurrence: event.currentTarget.value as CareRecurrence,
                    }))
                  }
                  value={formState.recurrence}
                >
                  <option value="One-off">One-off</option>
                  <option value="Monthly">Monthly - reset every month</option>
                </select>
              </label>

              <div className="flex items-end">
                <button
                  className="w-full rounded-2xl bg-[#c8f06e] px-5 py-3 text-xs font-semibold uppercase tracking-[0.12em] text-[#0d2029] transition hover:bg-white"
                  type="submit"
                >
                  Save reminder
                </button>
              </div>
            </div>
          </form>
        ) : null}

        <div className="mt-6">
          <div className="mb-4 flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
            <div>
              <p className="text-xs font-medium text-white/62">
                Live records for {activeProperty.name}
              </p>
              <p className="text-[11px] text-white/42">
                These are editable demo records and your added items are saved in this
                browser.
              </p>
            </div>
            <div className="flex flex-wrap gap-2">
              <button
                className="rounded-full border border-[#c8f06e]/45 bg-[#c8f06e] px-3.5 py-1.5 text-[11px] font-semibold uppercase tracking-[0.1em] text-[#0d2029] transition hover:bg-white"
                onClick={() => {
                  setFormState((current) => ({
                    ...current,
                    propertyId: activeProperty.id,
                    kind: "check",
                    category: "Certificate",
                    title: "",
                    amount: "",
                    provider: "",
                    audience: "Landlord",
                    recurrence: "One-off",
                  }));
                  setFilterKind("check");
                  setIsFormOpen(true);
                }}
                type="button"
              >
                Add certificate/check
              </button>
              {[
                ["all", "All"],
                ["bill", "Bills"],
                ["check", "Checks"],
              ].map(([kind, label]) => (
                <button
                  className={cn(
                    "rounded-full border px-3.5 py-1.5 text-[11px] font-semibold uppercase tracking-[0.1em] transition",
                    filterKind === kind
                      ? "border-[#c8f06e] bg-[#c8f06e] text-[#0d2029]"
                      : "border-white/12 text-white/58 hover:border-white/30 hover:text-white",
                  )}
                  key={kind}
                  onClick={() => setFilterKind(kind as "all" | CareKind)}
                  type="button"
                >
                  {label}
                </button>
              ))}
            </div>
          </div>

          <div className="grid gap-3">
            {visibleRecords.slice(0, 8).map((record) => (
              <RecordRow
                key={record.id}
                onDateChange={handleRecordDateChange}
                onRemove={handleRemoveRecord}
                onStatusChange={handleStatusChange}
                properties={properties}
                record={record}
              />
            ))}
          </div>
        </div>

        <div className="mt-7 flex justify-center gap-2">
          {properties.map((property, index) => (
            <button
              aria-current={index === activeIndex ? "true" : undefined}
              aria-label={`Show ${property.name}`}
              className={cn(
                "h-2.5 rounded-full transition",
                index === activeIndex
                  ? "w-10 bg-[#c8f06e]"
                  : "w-2.5 bg-white/60 hover:bg-[#c8f06e]/80",
              )}
              key={property.id}
              onClick={() => showProperty(index)}
              type="button"
            />
          ))}
        </div>
      </div>
    </section>
  );
}
