import { ref } from "vue";

import type { Meta, StoryFn } from "@storybook/vue3-vite";

import {
  getArgTypes,
  getSlotNames,
  getSlotsFragment,
  getDocsDescription,
} from "../../utils/storybook";
import { getRandomId } from "../../utils/helper";

import defaultConfig from "../config";

import UTable from "../UTable.vue";
import UButton from "../../ui.button/UButton.vue";
import ULink from "../../ui.button-link/ULink.vue";
import UNumber from "../../ui.text-number/UNumber.vue";
import UBadge from "../../ui.text-badge/UBadge.vue";
import URow from "../../ui.container-row/URow.vue";
import UIcon from "../../ui.image-icon/UIcon.vue";
import ULoader from "../../ui.loader/ULoader.vue";
import UInputSearch from "../../ui.form-input-search/UInputSearch.vue";
import UText from "../../ui.text-block/UText.vue";

import tooltip from "../../v.tooltip/vTooltip";
import type { Row, Props, ColumnObject } from "../types";
import { StickySide } from "../types";

interface UTableArgs extends Props {
  slotTemplate?: string;
  enum: "size";
  numberOfRows: number;
  row: Row | typeof getRow;
}

export default {
  id: "7010",
  title: "Data / Table",
  component: UTable,
  argTypes: {
    ...getArgTypes(UTable.__name),
    row: {
      table: {
        disable: true,
      },
    },
  },
  args: {
    columns: [
      { key: "orderId", label: "Order Id", thClass: "w-2/5" },
      { key: "customerName", label: "Customer Name" },
      { key: "status", label: "Status" },
      { key: "totalPrice", label: "Total Price" },
    ],
    rows: [
      {
        id: getRandomId(),
        orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
        customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][
          Math.floor(Math.random() * 4)
        ],
        status: ["Pending", "Shipped", "Delivered", "Cancelled"][Math.floor(Math.random() * 4)],
        totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
      },
      {
        id: getRandomId(),
        orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
        customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][
          Math.floor(Math.random() * 4)
        ],
        status: ["Pending", "Shipped", "Delivered", "Cancelled"][Math.floor(Math.random() * 4)],
        totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
      },
      {
        id: "row-3",
        orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
        customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][
          Math.floor(Math.random() * 4)
        ],
        status: ["Pending", "Shipped", "Delivered", "Cancelled"][Math.floor(Math.random() * 4)],
        totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
      },
      {
        id: getRandomId(),
        orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
        customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][
          Math.floor(Math.random() * 4)
        ],
        status: ["Pending", "Shipped", "Delivered", "Cancelled"][Math.floor(Math.random() * 4)],
        totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
      },
    ],
  },
  parameters: {
    docs: {
      ...getDocsDescription(UTable.__name),
    },
  },
} as Meta;

function getDateDividerRow(rowAmount: number) {
  return Array(rowAmount)
    .fill({})
    .map((_, index) => {
      let rowDate = new Date().toString();

      if (index > 1) {
        const date = new Date();

        date.setFullYear(date.getFullYear());

        rowDate = date.toDateString();
      }

      return {
        id: getRandomId(),
        rowDate,
        orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
        customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][
          Math.floor(Math.random() * 4)
        ],
        status: ["Pending", "Shipped", "Delivered", "Cancelled"][Math.floor(Math.random() * 4)],
        totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
      };
    });
}

function getRow(numberOfRows: number) {
  return Array.from({ length: numberOfRows }, () => ({
    id: getRandomId(),
    orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
    customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][
      Math.floor(Math.random() * 4)
    ],
    status: ["Pending", "Shipped", "Delivered", "Cancelled"][Math.floor(Math.random() * 4)],
    totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
  }));
}

const DefaultTemplate: StoryFn<UTableArgs> = (args: UTableArgs) => ({
  components: { UTable, UButton, ULink, UNumber, UBadge, URow, UIcon, ULoader },
  setup: () => ({ args, slots: getSlotNames(UTable.__name) }),
  template: `
    <UTable v-bind="args">
      ${args.slotTemplate || getSlotsFragment("")}
    </UTable>
  `,
});

export const Default = DefaultTemplate.bind({});
Default.args = {};

export const Loading: StoryFn<UTableArgs> = (args: UTableArgs) => ({
  components: { UTable, UButton },
  setup: () => ({ args }),
  template: `
    <UButton
      label="Toggle loading"
      size="sm"
      class="mb-4"
      @click="args.loading = !args.loading"
    />

    <UTable
      :columns="[
        { key: 'orderId', label: 'Order Id', thClass: 'w-2/5' },
        { key: 'customerName', label: 'Customer Name' },
        { key: 'status', label: 'Status' },
        { key: 'totalPrice', label: 'Total Price' },
      ]"
      :rows="[]"
      :loading="args.loading"
    />
  `,
});
Loading.parameters = {
  docs: {
    description: {
      story: "Set table loader state.",
    },
  },
};

export const EmptyCellLabel = DefaultTemplate.bind({});
EmptyCellLabel.args = {
  emptyCellLabel: "NO DATA",
  rows: [
    {
      id: getRandomId(),
      orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
      customerName: "",
      status: "",
      totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
    },
  ],
};
EmptyCellLabel.parameters = {
  docs: {
    description: {
      story: "Label to display for empty cell values.",
    },
  },
};

export const Nesting = DefaultTemplate.bind({});
Nesting.args = {
  rows: [
    {
      id: getRandomId(),
      orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
      customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][
        Math.floor(Math.random() * 4)
      ],
      status: ["Pending", "Shipped", "Delivered", "Cancelled"][Math.floor(Math.random() * 4)],
      totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
    },
    {
      id: getRandomId(),
      orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
      customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][
        Math.floor(Math.random() * 4)
      ],
      status: ["Processing", "Shipped", "Delivered", "Cancelled"][Math.floor(Math.random() * 4)],
      totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
      row: [
        {
          id: getRandomId(),
          orderId: "Suborder-1",
          customerName: "",
          status: "",
          totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
          row: {
            id: getRandomId(),
            orderId: "Extra Services",
            customerName: "",
            status: "",
            totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
          },
        },
        {
          id: getRandomId(),
          orderId: "Suborder-2",
          customerName: "",
          status: "",
          totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
          row: {
            id: getRandomId(),
            orderId: "Extra Services",
            customerName: "",
            status: "",
            totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
          },
        },
      ],
    },
  ],
};
Nesting.parameters = {
  docs: {
    description: {
      story:
        "If you need to have nested row(s) in the table, you can use the `row` key inside a row object.",
    },
  },
};

export const CellClasses = DefaultTemplate.bind({});
CellClasses.args = {
  rows: [
    {
      id: getRandomId(),
      orderId: { value: `ORD-${Math.floor(Math.random() * 10000)}`, class: "bg-error/25" },
      customerName: "John Doe",
      status: "Cancelled",
      totalPrice: "$18.92",
    },
    {
      id: getRandomId(),
      class: "!bg-success/25",
      orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
      customerName: "Bob Smith",
      status: "Delivered",
      totalPrice: "$173.11",
    },
    {
      id: getRandomId(),
      orderId: {
        value: `ORD-${Math.floor(Math.random() * 10000)}`,
        contentClass: "text-green-300 line-through",
      },
      customerName: "Helen Williams",
      status: "Delivered",
      totalPrice: "$314.26",
    },
  ],
};
CellClasses.parameters = {
  docs: {
    description: {
      story:
        // eslint-disable-next-line vue/max-len
        "To apply classes to a table content, you may use different approaches: <br/> 1. Pass a string with classes to the `class` key in a row object (classes are applied to the whole row). <br/> 2. Pass a string with classes to the `class` key in a cell object (classes are applied to the table cell, while the value is passed via a `value` key). <br/> 3. Pass a string with classes to the `contentClass` key in a cell object (classes are applied to the cell content, while the value is passed via a `value` key).",
    },
  },
};

export const Empty = DefaultTemplate.bind({});
Empty.args = { rows: [] };

export const Selectable = DefaultTemplate.bind({});
Selectable.args = { selectable: true };

export const StickyHeader = DefaultTemplate.bind({});
StickyHeader.args = {
  rows: getRow(10),
  selectable: true,
  stickyHeader: true,
};
StickyHeader.parameters = {
  docs: {
    story: {
      inline: false,
      iframeHeight: 450,
    },
    source: {
      code: `
        <UTable
          sticky-header
          selectable
          :columns="[
            {'key':'orderId','label':'Order Id','thClass':'w-2/5'},
            {'key':'customerName','label':'Customer Name'},
            {'key':'status','label':'Status'},
            {'key':'totalPrice','label':'Total Price'}
          ]"
          :rows="[
            {
              'id': 'xsJCpznyamFLstB',
              'orderId': 'ORD-2339',
              'customerName': 'James Wilson',
              'status': 'Pending',
              'totalPrice': '$240.15'
            },
            {
              'id': 'RMHWrRRYAfpmPtR',
              'orderId': 'ORD-2927',
              'customerName': 'James Wilson',
              'status': 'Cancelled',
              'totalPrice': '$350.40'
            },
            {
              'id': 'HqCFkWgubiNvVhd',
              'orderId': 'ORD-5975',
              'customerName': 'Alice Johnson',
              'status': 'Shipped',
              'totalPrice': '$180.41'
            },
            {
              'id': 'nQyrwynyqIRUTPM',
              'orderId': 'ORD-8643',
              'customerName': 'Michael Smith',
              'status': 'Pending',
              'totalPrice': '$318.30'
            }
          ]"
        />
      `,
    },
  },
};

export const StickyFooter = DefaultTemplate.bind({});
StickyFooter.args = {
  rows: getRow(10),
  selectable: true,
  stickyFooter: true,
  slotTemplate: `
    <template #footer>
      <td colspan="4" class="p-4">
        <p class="font-semibold text-accented">
          📊 Summary: 50 transactions processed | Total Revenue: <strong>$12,345.67</strong>
        </p>
      </td>
    </template>
  `,
};
StickyFooter.parameters = {
  docs: {
    story: {
      inline: false,
      iframeHeight: 450,
    },
    source: {
      code: `
        <UTable
          sticky-footer
          selectable
          :columns="[
            {'key':'orderId','label':'Order Id','thClass':'w-2/5'},
            {'key':'customerName','label':'Customer Name'},
            {'key':'status','label':'Status'},
            {'key':'totalPrice','label':'Total Price'}
          ]"
          :rows="[
            {
              'id': 'xsJCpznyamFLstB',
              'orderId': 'ORD-2339',
              'customerName': 'James Wilson',
              'status': 'Pending',
              'totalPrice': '$240.15'
            },
            {
              'id': 'RMHWrRRYAfpmPtR',
              'orderId': 'ORD-2927',
              'customerName': 'James Wilson',
              'status': 'Cancelled',
              'totalPrice': '$350.40'
            },
            {
              'id': 'HqCFkWgubiNvVhd',
              'orderId': 'ORD-5975',
              'customerName': 'Alice Johnson',
              'status': 'Shipped',
              'totalPrice': '$180.41'
            },
            {
              'id': 'nQyrwynyqIRUTPM',
              'orderId': 'ORD-8643',
              'customerName': 'Michael Smith',
              'status': 'Pending',
              'totalPrice': '$318.30'
            }
          ]"
        />
      `,
    },
  },
};

export const Compact = DefaultTemplate.bind({});
Compact.args = { compact: true };
Compact.parameters = {
  docs: {
    description: {
      story: "`compact` prop makes the table compact (fewer spacings).",
    },
  },
};

export const DateDivider = DefaultTemplate.bind({});
DateDivider.args = { dateDivider: true, rows: getDateDividerRow(4) };
DateDivider.parameters = {
  docs: {
    description: {
      story: "Show date divider line between dates.",
    },
  },
};

export const DateDividerCustomLabel = DefaultTemplate.bind({});
DateDividerCustomLabel.args = {
  rows: getDateDividerRow(4),
  dateDivider: [
    {
      date: getDateDividerRow(4).at(2)!.rowDate,
      label: new Date().toLocaleDateString(undefined, {
        weekday: "long",
        day: "2-digit",
        month: "long",
        year: "numeric",
      }),
      config: { label: "!text-orange-400", divider: "!border-orange-300" },
    },
  ],
};
DateDividerCustomLabel.parameters = {
  docs: {
    description: {
      story:
        "You can customize date divider by passing necessary data in `date`, `label` and `config` object keys.",
    },
  },
};

export const StickyColumns: StoryFn<UTableArgs> = (args: UTableArgs) => ({
  components: { UTable, URow, UBadge, UButton, UIcon },
  directives: { tooltip },
  setup() {
    function toggleLeft(key: string) {
      const column = args.columns.find((item) => (item as ColumnObject).key === key);

      if (!column || typeof column === "string") return;

      column.sticky = column.sticky === StickySide.Left ? undefined : StickySide.Left;
      args.columns = args.columns.slice();
    }

    function toggleRight(key: string) {
      const column = args.columns.find((item) => (item as ColumnObject).key === key);

      if (!column || typeof column === "string") return;

      column.sticky = column.sticky === StickySide.Right ? undefined : StickySide.Right;
      args.columns = args.columns.slice();
    }

    function isPinned(key: string, side: string) {
      const column = args.columns.find((item) => (item as ColumnObject).key === key);

      if (!column || typeof column === "string") return;

      return column?.sticky === side;
    }

    return { args, toggleLeft, toggleRight, isPinned };
  },
  template: `
    <UTable v-bind="args">
      <template #header-orderId="{ column }">
        <URow gap="2xs" align="center">
          <div>{{ column.label }}</div>
          <UIcon
            name="keep"
            size="xs"
            interactive
            v-tooltip="isPinned('orderId', 'left') ? 'Unpin left' : 'Pin left'"
            :color="isPinned('orderId', 'left') ? 'primary' : 'inherit'"
            @click.stop="toggleLeft('orderId')"
          />
        </URow>
      </template>

      <template #header-customerName="{ column }">
        <URow gap="2xs" align="center">
          <div>{{ column.label }}</div>
          <UIcon
            name="keep"
            size="xs"
            interactive
            v-tooltip="isPinned('customerName', 'left') ? 'Unpin left' : 'Pin left'"
            :color="isPinned('customerName', 'left') ? 'primary' : 'inherit'"
            @click.stop="toggleLeft('customerName')"
          />
        </URow>
      </template>

      <template #header-email="{ column }">
        <URow gap="2xs" align="center">
          <div>{{ column.label }}</div>
          <UIcon
            name="keep"
            size="xs"
            interactive
            v-tooltip="isPinned('email', 'left') ? 'Unpin left' : 'Pin left'"
            :color="isPinned('email', 'left') ? 'primary' : 'inherit'"
            @click.stop="toggleLeft('email')"
          />
        </URow>
      </template>

      <template #header-totalPrice="{ column }">
        <URow gap="2xs" align="center">
          <div>{{ column.label }}</div>
          <UIcon
            name="keep"
            size="xs"
            interactive
            v-tooltip="isPinned('totalPrice', 'right') ? 'Unpin right' : 'Pin right'"
            :color="isPinned('totalPrice', 'right') ? 'primary' : 'inherit'"
            @click.stop="toggleRight('totalPrice')"
          />
        </URow>
      </template>

      <template #header-action="{ column }">
        <URow gap="2xs" align="center">
          <div>{{ column.label }}</div>
          <UIcon
            name="keep"
            size="xs"
            interactive
            v-tooltip="isPinned('action', 'right') ? 'Unpin right' : 'Pin right'"
            :color="isPinned('action', 'right') ? 'primary' : 'inherit'"
            @click.stop="toggleRight('action')"
          />
        </URow>
      </template>

      <template #cell-status="{ value }">
        <UBadge
          :label="value"
          variant="soft"
          :color="
            value === 'Delivered' ? 'success' :
            value === 'Cancelled' ? 'error' :
            value === 'Pending' ? 'notice' :
            value === 'Shipped' ? 'info' : ''
          "
        />
      </template>

      <template #cell-action>
        <UButton label="View" size="xs" variant="soft" />
      </template>
    </UTable>
  `,
});
StickyColumns.args = {
  columns: [
    { key: "orderId", label: "Order ID", sticky: "left" },
    { key: "customerName", label: "Customer Name", thClass: "min-w-[200px]" },
    { key: "email", label: "Email", thClass: "min-w-[250px]", sticky: "left" },
    { key: "phone", label: "Phone", thClass: "min-w-[150px]" },
    { key: "address", label: "Address", thClass: "min-w-[300px]" },
    { key: "city", label: "City", thClass: "min-w-[150px]" },
    { key: "country", label: "Country", thClass: "min-w-[150px]" },
    { key: "status", label: "Status", thClass: "min-w-[120px]" },
    { key: "totalPrice", label: "Total Price", thClass: "min-w-[120px]" },
    { key: "action", label: "Actions", sticky: "right", thClass: "min-w-[100px]" },
  ],
  rows: [
    {
      id: "row-1",
      orderId: "ORD-1001",
      customerName: "Alice Johnson",
      email: "alice.johnson@example.com",
      phone: "+1 (555) 123-4567",
      address: "123 Main Street, Apt 4B",
      city: "New York",
      country: "USA",
      status: "Delivered",
      totalPrice: "$245.99",
      action: "View",
    },
    {
      id: "row-2",
      orderId: "ORD-1002",
      customerName: "Michael Smith",
      email: "michael.smith@example.com",
      phone: "+1 (555) 234-5678",
      address: "456 Oak Avenue, Suite 200",
      city: "Los Angeles",
      country: "USA",
      status: "Pending",
      totalPrice: "$189.50",
      action: "View",
    },
    {
      id: "row-3",
      orderId: "ORD-1003",
      customerName: "Emma Brown",
      email: "emma.brown@example.com",
      phone: "+1 (555) 345-6789",
      address: "789 Pine Road, Building C",
      city: "Chicago",
      country: "USA",
      status: "Shipped",
      totalPrice: "$312.75",
      action: "View",
    },
    {
      id: "row-4",
      orderId: "ORD-1004",
      customerName: "James Wilson",
      email: "james.wilson@example.com",
      phone: "+1 (555) 456-7890",
      address: "321 Elm Street, Floor 3",
      city: "Houston",
      country: "USA",
      status: "Cancelled",
      totalPrice: "$156.20",
      action: "View",
    },
    {
      id: "row-5",
      orderId: "ORD-1005",
      customerName: "Sophia Davis",
      email: "sophia.davis@example.com",
      phone: "+1 (555) 567-8901",
      address: "654 Maple Drive, Unit 12",
      city: "Phoenix",
      country: "USA",
      status: "Delivered",
      totalPrice: "$428.90",
      action: "View",
    },
  ],
};
StickyColumns.parameters = {
  docs: {
    description: {
      story:
        "Pin columns to the left or right edge of the table when scrolling horizontally. " +
        "Use the header pin icons to toggle pinning for each column.",
    },
  },
};

export const HeaderCounterSlot = DefaultTemplate.bind({});
HeaderCounterSlot.args = {
  selectable: true,
  config: { headerCellCheckbox: "w-20" },
  slotTemplate: `
    <template #header-counter="{ total }">
      Total: {{ total }}
    </template>
  `,
};

export const HeaderKeySlot = DefaultTemplate.bind({});
HeaderKeySlot.args = {
  slotTemplate: `
    <template #header-status="{ column }">
      <UBadge :label="column.label" />
    </template>
  `,
};

export const HeaderActionsSlot = DefaultTemplate.bind({});
HeaderActionsSlot.args = {
  selectable: true,
  selectedRows: [{ id: "row-3" }],
  slotTemplate: `
    <template #header-actions>
      <URow gap="2xs">
        <UButton
          label="Edit"
          variant="ghost"
          color="primary"
          size="sm"
        />

        <UButton
          label="Delete"
          variant="ghost"
          color="primary"
          size="sm"
        />
      </URow>
    </template>
  `,
};

export const BeforeHeaderSlot = DefaultTemplate.bind({});
BeforeHeaderSlot.args = {
  slotTemplate: `
    <template #before-header="{ colsCount, classes }">
      <th :colspan="colsCount" :class="classes">📊 Latest orders report.</th>
    </template>
  `,
};

export const BeforeFirstRowSlot = DefaultTemplate.bind({});
BeforeFirstRowSlot.args = {
  slotTemplate: `
    <template #before-first-row>
      <UButton label="Load planned" size="xs" class="my-3" />
    </template>
  `,
};

export const CellSlots = DefaultTemplate.bind({});
CellSlots.args = {
  slotTemplate: `
    <template #cell-orderId="{ value }">
      <ULink :label="value" color="success" />
    </template>

    <template #cell-status="{ value }">
      <UBadge
        :label="value"
        variant="soft"
        :color="
          value === 'Delivered' ? 'success' :
          value === 'Cancelled' ? 'error' :
          value === 'Pending' ? 'notice' :
          value === 'Shipped' ? 'info' : ''
        "
      />
    </template>

    <template #cell-totalPrice="{ value }">
      <UNumber :value="value.slice(1)" currency="€" currency-align="left" />
    </template>
  `,
};

export const ExpandSlot = DefaultTemplate.bind({});
ExpandSlot.args = {
  rows: [
    {
      id: getRandomId(),
      orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
      customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][
        Math.floor(Math.random() * 4)
      ],
      status: ["Pending", "Shipped", "Delivered", "Cancelled"][Math.floor(Math.random() * 4)],
      totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
    },
    {
      id: getRandomId(),
      orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
      customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][
        Math.floor(Math.random() * 4)
      ],
      status: ["Processing", "Shipped", "Delivered", "Cancelled"][Math.floor(Math.random() * 4)],
      totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
      row: [
        {
          id: getRandomId(),
          orderId: "Suborder-1",
          customerName: "",
          status: "",
          totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
          row: {
            id: getRandomId(),
            orderId: "Extra Services",
            customerName: "",
            status: "",
            totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
          },
        },
        {
          id: getRandomId(),
          orderId: "Suborder-2",
          customerName: "",
          status: "",
          totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
          row: {
            id: getRandomId(),
            orderId: "Extra Services",
            customerName: "",
            status: "",
            totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
          },
        },
      ],
    },
  ],
  slotTemplate: `
    <template #expand="{ expanded }">
      <UButton
        :icon="expanded ? 'keyboard_arrow_up' : 'keyboard_arrow_down'"
        variant="soft"
        size="2xs"
        square
      />
    </template>
  `,
};

export const NestedRowSlot = DefaultTemplate.bind({});
NestedRowSlot.args = {
  columns: [
    { key: "orderId", label: "Order Id" },
    { key: "customerName", label: "Customer Name" },
    { key: "status", label: "Status" },
  ],
  rows: [
    {
      id: getRandomId(),
      orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
      customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][
        Math.floor(Math.random() * 4)
      ],
      status: ["Processing", "Shipped", "Delivered", "Cancelled"][Math.floor(Math.random() * 4)],
      totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
    },
    {
      id: getRandomId(),
      orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
      customerName: "John Doe",
      status: "Processing",
      row: {
        id: getRandomId(),
        rows: [
          {
            id: getRandomId(),
            category: "Gadgets",
            itemName: "Ergonomic Mouse",
            quantity: 2,
          },
          {
            id: getRandomId(),
            category: "Gadgets",
            itemName: "Wireless Keyboard",
            quantity: 1,
          },
          {
            id: getRandomId(),
            category: "Electronics",
            itemName: "USB-C Hub",
            quantity: 3,
          },
        ],
      },
    },
    {
      id: getRandomId(),
      orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
      customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][
        Math.floor(Math.random() * 4)
      ],
      status: ["Processing", "Shipped", "Delivered", "Cancelled"][Math.floor(Math.random() * 4)],
      totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
    },
    {
      id: getRandomId(),
      orderId: `ORD-${Math.floor(Math.random() * 10000)}`,
      customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][
        Math.floor(Math.random() * 4)
      ],
      status: ["Processing", "Shipped", "Delivered", "Cancelled"][Math.floor(Math.random() * 4)],
      totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
    },
  ],
  slotTemplate: `
    <template #nested-row="{ row }">
      <div class="p-4 bg-lifted">
          <UTable
            :columns="[
              { key: 'category', label: 'Category' },
              { key: 'itemName', label: 'Product' },
              { key: 'quantity', label: 'Quantity' },
            ]"
            :rows="row.rows"
            compact
          />
      </div>
    </template>
  `,
};

export const AfterLastRowSlot = DefaultTemplate.bind({});
AfterLastRowSlot.args = {
  slotTemplate: `
    <template #after-last-row="{ colsCount, classes }">
      <td :colspan="colsCount" :class="classes">
        <URow block justify="end">
          Totals:
          <UNumber
            color="success"
            :value="${Math.random() * 500}"
            currency="$"
          />
        </URow>
      </td>
    </template>
  `,
};

export const EmptyStateSlot = DefaultTemplate.bind({});
EmptyStateSlot.args = {
  rows: [],
  config: {
    i18n: { ...defaultConfig.i18n, noData: "Fetching data..." },
    bodyEmptyStateCell: "py-10",
  },
  slotTemplate: `
    <template #empty-state>
      <ULoader loading :config="{ loader: 'mx-auto mb-4' }" />
      <p class="text-center">Fetching latest data, please wait...</p>
    </template>
  `,
};

export const FooterSlot = DefaultTemplate.bind({});
FooterSlot.args = {
  slotTemplate: `
    <template #footer>
      <td colspan="100%" class="px-2">
        🔍 For more detailed insights, please visit our data analysis page or reach out to support for assistance.
      </td>
    </template>
  `,
};

function generateNestedRows(count: number): Row[] {
  return Array.from({ length: count }, (_, i) => {
    const hasChildren = i % 10 === 0;
    const row: Row = {
      id: `row-${i}`,
      orderId: `ORD-${String(i).padStart(5, "0")}`,
      customerName: ["Alice Johnson", "Michael Smith", "Emma Brown", "James Wilson"][i % 4],
      status: ["Pending", "Shipped", "Delivered", "Cancelled"][i % 4],
      totalPrice: `$${(Math.random() * 500).toFixed(2)}`,
    };

    if (hasChildren) {
      row.row = Array.from({ length: 3 }, (_, j) => ({
        id: `row-${i}-child-${j}`,
        orderId: `SUB-${String(i).padStart(5, "0")}-${j + 1}`,
        customerName: "",
        status: ["Processing", "Packed", "Ready"][j % 3],
        totalPrice: `$${(Math.random() * 100).toFixed(2)}`,
      }));
    }

    return row;
  });
}

export const VirtualScroll: StoryFn<UTableArgs> = (args: UTableArgs) => ({
  components: { UTable, UBadge },
  setup() {
    const rows = generateNestedRows(100000);

    return { args, rows };
  },
  template: `
    <UTable
      :columns="[
        { key: 'orderId', label: 'Order ID', thClass: 'w-1/5' },
        { key: 'customerName', label: 'Customer Name' },
        { key: 'status', label: 'Status' },
        { key: 'totalPrice', label: 'Total Price' },
      ]"
      :rows="rows"
      compact
      virtual-scroll
      :row-height="46"
      :buffer-size="10"
    >
      <template #cell-status="{ value }">
        <UBadge
          :label="value"
          variant="soft"
          :color="
            value === 'Delivered' ? 'success' :
            value === 'Cancelled' ? 'error' :
            value === 'Pending' ? 'notice' :
            value === 'Shipped' || value === 'Processing' ? 'info' :
            value === 'Packed' || value === 'Ready' ? 'primary' : ''
          "
        />
      </template>
    </UTable>
  `,
});
VirtualScroll.parameters = {
  docs: {
    description: {
      story:
        "Virtual scrolling enables rendering of large datasets (100,000+ rows) with optimal performance. " +
        "Only visible rows are rendered in the DOM, with collapsible nested rows fully supported. " +
        "Use `virtualScroll` prop to enable, and configure `rowHeight`, `scrollHeight`, and `bufferSize` as needed.",
    },
  },
};

export const VirtualSearch: StoryFn<UTableArgs> = (args: UTableArgs) => ({
  components: { UTable, UInputSearch, UButton, URow, UText },
  setup() {
    const rows = generateNestedRows(100000);
    const search = ref("");
    const searchMatch = ref(-1);
    const totalMatches = ref(0);

    function onPrev() {
      if (totalMatches.value === 0) return;

      searchMatch.value = searchMatch.value <= 0 ? totalMatches.value - 1 : searchMatch.value - 1;
    }

    function onNext() {
      if (totalMatches.value === 0) return;

      searchMatch.value = searchMatch.value >= totalMatches.value - 1 ? 0 : searchMatch.value + 1;
    }

    return { args, rows, search, searchMatch, totalMatches, onPrev, onNext };
  },
  template: `
    <URow align="stretch" gap="xs" class="mb-4">
      <UInputSearch
        v-model="search"
        placeholder="Search in table..."
        size="md"
        @clear="searchMatch = -1"
      >
        <template #right>
          <UText :label="searchMatch + 1 + ' / ' + totalMatches" :wrap="false" class="ml-1" />
        </template>
      </UInputSearch>

      <UButton
        square
        size="sm"
        title="Prev"
        variant="soft"
        icon="keyboard_arrow_up"
        :disabled="totalMatches === 0"
        @click="onPrev"
      />

      <UButton
        square
        size="sm"
        title="Next"
        variant="soft"
        icon="keyboard_arrow_down"
        :disabled="totalMatches === 0"
        @click="onNext"
      />
    </URow>

    <UTable
      :columns="[
        { key: 'orderId', label: 'Order ID', thClass: 'w-1/5' },
        { key: 'customerName', label: 'Customer Name' },
        { key: 'status', label: 'Status' },
        { key: 'totalPrice', label: 'Total Price' },
      ]"
      :rows="rows"
      compact
      virtual-scroll
      :row-height="45"
      :buffer-size="10"
      :search="search"
      :search-match="searchMatch"
      @search="totalMatches = $event"
    />
  `,
});
VirtualSearch.parameters = {
  docs: {
    description: {
      story:
        "Search functionality with virtual scrolling. " +
        "Use `search` prop to pass a search string and `searchMatch` prop to highlight a specific match. " +
        "The `@search` event emits the total number of matches found. " +
        "Use Prev/Next buttons to navigate between matches.",
    },
  },
};
