import BookingStatus from "@/components/blocks/BookingStatus/bookingStatus";
import type { CuratedEventsBooking } from "@/lib/features/bookings/curated/types";
import type {
  CoreBookingStatus,
  CoreBookingUnit,
} from "@/lib/features/bookings/types";
import {
  Badge,
  Drawer,
  Group,
  MultiSelect,
  Stack,
  Tabs,
  Text,
  TextInput,
} from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { IconSearch } from "@tabler/icons-react";
import moment from "moment";
import { useEffect, useMemo, useState } from "react";
import { useLocation, useNavigate } from "react-router";
import {
  MemberDataTable,
  type MemberColumn,
} from "@/routes/members/_components/MemberDataTable";
import { MemberFilterTrigger } from "@/routes/members/_components/MemberFilters";
import { bookingRole } from "@/routes/members/_components/statusColors";
import promoStyles from "@/routes/promo-code-campaigns/_components/promo.module.css";

interface BookingTableData<T> {
  data: T[];
  totalRows: number;
}

export type BookingTabValue = "internal" | "external" | "curated";

const MembershipBookings: React.FC<{
  bookings: {
    internal: BookingTableData<CoreBookingUnit>;
    external: BookingTableData<CoreBookingUnit>;
  };
  curatedBookings?: BookingTableData<CuratedEventsBooking>;
  selectedBookingType?: BookingTabValue;
  /**
   * Drawer/modal embeds render a single table and must not write to the host
   * page URL, so they turn the type tabs off.
   */
  enableTypeTabs?: boolean;
}> = ({
  bookings,
  curatedBookings,
  selectedBookingType = "internal",
  enableTypeTabs = true,
}) => {
  const navigate = useNavigate();
  const { search } = useLocation();
  const [activeBookingType, setActiveBookingType] =
    useState<BookingTabValue>(selectedBookingType);
  const [bookingCache, setBookingCache] = useState(bookings);
  const [curatedBookingCache, setCuratedBookingCache] = useState(
    curatedBookings ?? { data: [], totalRows: 0 },
  );

  // Search and status live in the filter drawer, like the promo pages — the
  // table area itself stays uncluttered.
  const [filterOpened, filterDrawer] = useDisclosure(false);
  const [searchTerm, setSearchTerm] = useState("");
  const [statuses, setStatuses] = useState<string[]>([]);

  useEffect(() => {
    setBookingCache(bookings);
    setCuratedBookingCache(curatedBookings ?? { data: [], totalRows: 0 });
  }, [bookings, curatedBookings]);

  useEffect(() => {
    if (!enableTypeTabs) return;
    const urlType = new URLSearchParams(search).get("type");

    if (
      urlType === "internal" ||
      urlType === "external" ||
      urlType === "curated"
    ) {
      setActiveBookingType(urlType);
    }
  }, [search, enableTypeTabs]);

  const activeBookingsRaw =
    activeBookingType === "external"
      ? bookingCache.external
      : bookingCache.internal;

  const statusOptions = useMemo(() => {
    const source =
      activeBookingType === "curated"
        ? curatedBookingCache.data.map((booking) => booking.status)
        : activeBookingsRaw.data.map((booking) => booking.status);
    return Array.from(new Set(source.filter(Boolean))).map((status) => ({
      value: String(status),
      label: String(status).replaceAll("_", " ").toLowerCase(),
    }));
  }, [activeBookingType, activeBookingsRaw, curatedBookingCache]);

  const matches = (fields: (string | number | null | undefined)[]) => {
    const term = searchTerm.trim().toLowerCase();
    if (!term) return true;
    return fields
      .filter((value) => value !== null && value !== undefined)
      .some((value) => String(value).toLowerCase().includes(term));
  };

  const filteredBookings = useMemo(
    () =>
      activeBookingsRaw.data.filter((booking) => {
        if (statuses.length && !statuses.includes(String(booking.status)))
          return false;
        return matches([
          booking.booking_id,
          booking.id,
          booking.unit_name,
          booking.entity_type,
          booking.destination?.name,
        ]);
      }),
    [activeBookingsRaw, statuses, searchTerm],
  );

  const filteredCurated = useMemo(
    () =>
      curatedBookingCache.data.filter((booking) => {
        if (statuses.length && !statuses.includes(String(booking.status)))
          return false;
        return matches([
          booking.booking_id,
          booking.event_name,
          booking.viewpoint_booking_number,
        ]);
      }),
    [curatedBookingCache, statuses, searchTerm],
  );

  const activeFilterCount = (searchTerm ? 1 : 0) + (statuses.length ? 1 : 0);

  const handleBookingTypeChange = (value: string | null) => {
    if (!value) {
      return;
    }

    setActiveBookingType(value as BookingTabValue);
    setStatuses([]);

    if (!enableTypeTabs) return;
    const searchParams = new URLSearchParams(search);
    searchParams.set("tab", "bookings");
    searchParams.set("type", value);
    searchParams.set("page", "1");
    navigate(`?${searchParams.toString()}`);
  };

  return (
    <Stack px={28} gap={12}>
      <Group justify="space-between" align="center">
        {enableTypeTabs ? (
          <Tabs value={activeBookingType} onChange={handleBookingTypeChange}>
            <Tabs.List>
              {BOOKING_TABS.map((tab) => (
                <Tabs.Tab key={tab.value} value={tab.value} px={8} py={9}>
                  <Text fz={12} fw={400}>
                    {tab.label}
                  </Text>
                </Tabs.Tab>
              ))}
            </Tabs.List>
          </Tabs>
        ) : (
          <span />
        )}
        <MemberFilterTrigger
          activeCount={activeFilterCount}
          onClick={filterDrawer.open}
        />
      </Group>

      {activeBookingType === "curated" ? (
        <MemberDataTable
          key="curated"
          rows={filteredCurated}
          columns={curatedColumns}
          minWidth={1200}
          rowKey={(row, index) => `${row.id ?? index}`}
          emptyMessage="No Bookings Found"
        />
      ) : (
        <MemberDataTable
          key={activeBookingType}
          rows={filteredBookings}
          columns={bookingColumns}
          minWidth={1500}
          rowKey={(row, index) => `${row.id ?? index}`}
          onRowClick={(row) =>
            navigate(`/admin/bookings/${row.booking_id}?unit=${row.id}`)
          }
          emptyMessage="No Bookings Found"
        />
      )}

      <Drawer
        opened={filterOpened}
        onClose={filterDrawer.close}
        position="right"
        size={360}
        title={
          <Text fw={600} fz={15}>
            Filter Bookings
          </Text>
        }
      >
        <Stack gap="lg">
          <TextInput
            label="Search"
            description="Booking, unit, resort or event"
            leftSection={<IconSearch size={15} />}
            value={searchTerm}
            onChange={(event) => setSearchTerm(event.currentTarget.value)}
          />
          <MultiSelect
            label="Status"
            data={statusOptions}
            value={statuses}
            onChange={setStatuses}
            searchable
            clearable
          />
        </Stack>
      </Drawer>
    </Stack>
  );
};

export default MembershipBookings;

const BOOKING_TABS: { label: string; value: BookingTabValue }[] = [
  { label: "Internal Property Bookings", value: "internal" },
  { label: "External Bookings", value: "external" },
  { label: "Curated Events Bookings", value: "curated" },
];

const bookingColumns: MemberColumn<CoreBookingUnit>[] = [
  {
    key: "booking_id",
    header: "Booking Id",
    numeric: true,
    render: (row) => <Text fw={600}>{row.booking_id}</Text>,
  },
  { key: "id", header: "Unit Id", numeric: true, render: (row) => row.id },
  {
    key: "entity_type",
    header: "Booking Type",
    // Same --role-internal / --role-curated colours as the promo bookings donut.
    render: (row) => (
      <span
        className={promoStyles.dataBadge}
        data-role={bookingRole(row.entity_type)}
      >
        {row.entity_type?.replaceAll("_", " ").toLowerCase()}
      </span>
    ),
  },
  {
    key: "unit_name",
    header: "Unit Name",
    render: (row) => row.unit_name ?? "NA",
  },
  {
    key: "resort_name",
    header: "Resort Name",
    render: (row) => row?.destination?.name ?? "NA",
  },
  {
    key: "check_in",
    header: "Check In",
    render: (row) =>
      row.check_in_date ? moment(row.check_in_date).format("YYYY-MM-DD") : "-",
  },
  {
    key: "check_out",
    header: "Check Out",
    render: (row) =>
      row.check_out_date
        ? moment(row.check_out_date).format("YYYY-MM-DD")
        : "-",
  },
  {
    key: "adults",
    header: "Adult",
    numeric: true,
    render: (row) => row.adults,
  },
  {
    key: "children",
    header: "Children",
    numeric: true,
    render: (row) => row.children,
  },
  {
    key: "infants",
    header: "Infants",
    numeric: true,
    render: (row) => row.infants,
  },
  {
    key: "status",
    header: "Status",
    render: (row) => <BookingStatus status={row.status} />,
  },
];

const curatedColumns: MemberColumn<CuratedEventsBooking>[] = [
  {
    key: "booking_id",
    header: "Booking Id",
    numeric: true,
    render: (row) => <Text fw={600}>{row.booking_id}</Text>,
  },
  {
    key: "viewpoint_booking_number",
    header: "Viewpoint Booking Number",
    render: (row) =>
      row.viewpoint_booking_number ? (
        <Badge variant="light" size="sm" radius={4}>
          {row.viewpoint_booking_number}
        </Badge>
      ) : (
        <Text c="dimmed">NA</Text>
      ),
  },
  { key: "event_name", header: "Event Name", render: (row) => row.event_name },
  {
    key: "event_start_date",
    header: "Start Date",
    render: (row) => moment(row.event_start_date).format("YYYY-MM-DD"),
  },
  {
    key: "event_end_date",
    header: "End Date",
    render: (row) => moment(row.event_end_date).format("YYYY-MM-DD"),
  },
  {
    key: "adults",
    header: "Adult",
    numeric: true,
    render: (row) => row.adults,
  },
  {
    key: "children",
    header: "Children",
    numeric: true,
    render: (row) => row.children,
  },
  {
    key: "infants",
    header: "Infants",
    numeric: true,
    render: (row) => row.infants,
  },
  {
    key: "status",
    header: "Status",
    render: (row) => <BookingStatus status={row.status as CoreBookingStatus} />,
  },
];
