import React, { useCallback, useEffect, useRef, useState } from 'react'
import { type Meta, type StoryObj } from '@storybook/react-vite'
import { Cell, Row } from 'react-sticky-table'

import { DocsTemplate } from '../../../.storybook'
import CustomTable from './CustomTable'
import {
  activeCellClass,
  hasStickyColumnStyle,
} from '../../services/HelperServiceTyped'
import JavascriptDisplay from '../JavascriptDisplay/JavascriptDisplay'

const meta: Meta<typeof CustomTable> = {
  title: 'Components/Tables/CustomTable',
  component: CustomTable,
  parameters: {
    layout: 'padded',
    design: {
      type: 'figma',
      url: 'https://www.figma.com/design/RvhKD82948FMQnh5MyCi0o/Web-Design-System?node-id=121-349&t=CdMnrLNv0lNFwXr0-0',
    },
    docs: {
      page: () => (
        <DocsTemplate
          figmaLink='https://www.figma.com/design/RvhKD82948FMQnh5MyCi0o/Web-Design-System?node-id=121-349&t=CdMnrLNv0lNFwXr0-0'
          description={
            <div>
              <div className='mb-4'>
                <code>CustomTable</code> is a component that allows you to
                display data in a table format. It is a wrapper around the{' '}
                <a
                  href='
              https://www.npmjs.com/package/react-sticky-table'
                  target='_blank'
                  className='text-blue'
                >
                  react-sticky-table
                </a>{' '}
                library. The biggest difference here is that the table does not
                fit all the standards set by the <code>StandardTable</code>, so
                a custom solution is necessary. Though the UI may look exactly
                the same, some custom functionality is needed for a requirement,
                making this component necessary. If at all possible, the
                recommendation is to use the <code>StandardTable</code>{' '}
                component.
              </div>
              <br />
              <div>
                Some important notes to keep in mind while implementing the{' '}
                <code>CustomTable</code>:
              </div>
              <ul>
                <li>
                  Passing <code>children</code> to the <code>CustomTable</code>{' '}
                  is required. A row component should be created and then mapped
                  over to display the table rows correctly.
                  <JavascriptDisplay
                    text={`{ data.map((item, index) => (
  <NewRowComponent
    key={item['id']}
    {...componentProps}
  />
)}`}
                  />
                </li>
                <li>
                  {' '}
                  We must make sure that our column values show a{' '}
                  <code>semi-bold</code> font weight when that column is
                  currently being sorted. To do this, the{' '}
                  <code>activeCellClass</code> function can be imported from
                  react-ui. Here is an example:
                  <JavascriptDisplay
                    text={`className={activeCellClass({
    cells: ['seller_id'],
    activeName: tableSortBy.prop,
  })
}}
                    `}
                  />
                </li>
                <li>
                  If the table has <code>stickyColumns</code> passed in, then
                  the correct class names need to be applied to the cells. Here
                  are the criteria:
                  <ol>
                    <li>
                      Sticky Left Columns: The last <code>Cell</code> in the
                      left sticky columns needs to have the class{' '}
                      <code>last-sticky-cell-left</code>. This will correctly
                      style the column so it is apparent that the column is
                      sticky. Generally, only one column is "sticky" so this
                      would likely be the first <code>Cell</code> that needs
                      this class. In addition to this, the first{' '}
                      <code>Cell</code> that is outside of the left sticky
                      columns needs to receive the{' '}
                      <code>extra-left-padding</code> class in order to have
                      sufficient padding for the column.
                    </li>
                    <li>
                      Sticky Right Columns: The first <code>Cell</code> in the
                      sticky right columns group needs to have the classes{' '}
                      <code>first-sticky-cell-right extra-left-padding</code>.
                      This will give sufficient padding and correctly style the
                      column.
                    </li>
                  </ol>
                </li>
                <li>
                  There is no mobile version associated with this table. If a
                  mobile version is needed, a custom mobile instance will need
                  to be created.
                </li>
              </ul>
            </div>
          }
        />
      ),
    },
  },
}

export default meta

type Story = StoryObj<typeof CustomTable>

type DataItem = {
  isTotalRow: boolean
  name: string
  asin: string
  multiple: { value: number; change: number }
  is_map: string
  is_enabled: string
  price: number
  map_price: number
}

const tableDummyData = (pageNum: number): DataItem[] => {
  const data: DataItem[] = []
  for (let i = 1; i <= 20; i++) {
    const num = pageNum > 1 ? (pageNum - 1) * 20 + i : i
    data.push({
      isTotalRow: i === 1 && num === 1,
      name: `Product Name ${num}`,
      asin: `Test ASIN ${num}`,
      multiple: { value: 32 + num, change: (num % 3 ? 1 : -1) * i },
      is_map: num % 2 ? 'Yes' : num % 3 ? 'No' : '',
      is_enabled: num % 2 ? 'Disabled' : 'Enabled',
      price: 12 * num + 1,
      map_price: 12 * num + 2,
    })
  }
  return data
}

type TableColumnType = {
  cellName: keyof DataItem
  cellIndex: number
}

const tableHeaders = [
  {
    id: 1,
    name: 'name',
    label: 'Name',
  },
  { id: 2, name: 'asin', label: 'ASIN' },
  {
    id: 3,
    label: 'Multiple Values Example',
    options: [
      {
        name: 'multiple',
        label: 'Main Value',
      },
      {
        name: 'change__multiple',
        label: 'Change Value',
      },
    ],
  },
  { id: 4, name: 'is_map', label: 'MAP' },
  { id: 5, name: 'is_enabled', label: 'Status' },
  { id: 6, name: 'price', label: 'Price' },
  { id: 7, name: 'map_price', label: 'MAP Price' },
]
const tableColumns: TableColumnType[] = [
  {
    cellName: 'name',
    cellIndex: 1,
  },
  {
    cellName: 'asin',
    cellIndex: 2,
  },
  {
    cellName: 'multiple',
    cellIndex: 3,
  },
  {
    cellName: 'is_map',
    cellIndex: 4,
  },
  {
    cellName: 'is_enabled',
    cellIndex: 5,
  },
  {
    cellName: 'price',
    cellIndex: 6,
  },
  {
    cellName: 'map_price',
    cellIndex: 7,
  },
]

const Template: Story = {
  render: function Render(args) {
    const [state, setState] = useState<{
      data: DataItem[]
      loading: boolean
      pageNumber: number
    }>({
      data: [],
      loading: false,
      pageNumber: 1,
    })
    const { data, loading, pageNumber } = state

    const [sort, setSort] = useState({
      prop: 'name',
      flip: false,
    })

    const dataTimeout = useRef<ReturnType<typeof setTimeout>>()
    const getData = useCallback((pageNum: number) => {
      if (pageNum === 1) {
        setState((prevState) => ({
          ...prevState,
          loading: true,
        }))
      }
      dataTimeout.current = setTimeout(() => {
        setState((prevState) => ({
          ...prevState,
          data: prevState.data.concat(tableDummyData(pageNum)),
          pageNumber: pageNum + 1,
          loading: false,
        }))
      }, 500)
    }, [])

    const setSortBy = (sortObj: {
      activeColumn: string
      direction: boolean
    }) => {
      setSort({
        prop: sortObj.activeColumn,
        flip: sortObj.direction,
      })
    }
    useEffect(() => {
      getData(1)
    }, [getData])

    useEffect(() => {
      return () => {
        clearTimeout(dataTimeout.current as ReturnType<typeof setTimeout>)
      }
    }, [])

    const tableProps = {
      ...args,
      hasData: args.hasData ?? data?.length > 0,
      hasMore: true,
      successStatus: true,
      loading: args.loading ?? loading,
      tableId: 'demo-table',
      noDataFields: {
        primaryText: `No Data Found`,
        secondaryText: `We could not find any data for the selected criteria.`,
      },
      getData: () => getData(pageNumber),
      ...(args.tableHeaderProps
        ? { tableHeaderProps: args.tableHeaderProps }
        : {}),
    }
    let sortProps = {}
    if (!args.noSort) {
      sortProps = { sort: setSortBy, sortBy: sort }
    }
    return (
      <CustomTable {...tableProps} {...sortProps}>
        {data.map((e) => (
          <Row key={e.name}>
            {tableColumns.map((tc) => {
              const value =
                tc.cellName === 'multiple' ? (
                  <div>
                    <div
                      className={
                        !args.noSort && sort.prop === 'multiple'
                          ? 'font-semibold'
                          : ''
                      }
                    >
                      {e.multiple.value}
                    </div>
                    <div
                      className={`mt-1 ${
                        !args.noSort && sort.prop === 'change__multiple'
                          ? 'font-semibold'
                          : ''
                      } ${e.multiple.change < 0 ? 'text-red' : 'text-green'}`}
                    >
                      {e.multiple.change}
                    </div>
                  </div>
                ) : (
                  <span
                    className={
                      !args.noSort && sort.prop === tc.cellName
                        ? 'font-semibold'
                        : ''
                    }
                  >
                    {e[tc.cellName]}
                  </span>
                )
              return (
                <Cell
                  key={`${e.name}-${tc.cellName}`}
                  className={`${
                    !args.noSort
                      ? activeCellClass({
                          cells: [tc.cellName, `change__${tc.cellName}`],
                          activeName: sort.prop,
                        })
                      : ''
                  } ${hasStickyColumnStyle({
                    colIndex: tc.cellIndex,
                    stickyLeftColumn: args.stickyTableConfig?.left,
                    stickyRightColumn: args.stickyTableConfig?.right,
                    tableHeadersLength: tableHeaders.length,
                  })}`}
                >
                  {value}
                </Cell>
              )
            })}
          </Row>
        ))}
      </CustomTable>
    )
  },
}

export const Basic: Story = {
  ...Template,
  args: {
    headers: tableHeaders,
    stickyTableConfig: {
      left: 1,
      right: 0,
    },
  },
}

export const CustomHeight: Story = {
  ...Template,
  args: {
    headers: tableHeaders,
    customHeight: '300px',
  },
}

export const CustomWidth: Story = {
  ...Template,
  args: {
    headers: tableHeaders,
    customWidth: '400px',
    customHeight: '400px',
  },
}

export const StickyColumns: Story = {
  ...Template,
  args: {
    headers: tableHeaders,
    customHeight: '400px',
    stickyTableConfig: {
      left: 2,
      right: 1,
    },
  },
}

export const NoData: Story = {
  ...Template,
  args: {
    headers: tableHeaders,
    customHeight: '400px',
    hasData: false,
  },
}

export const TableHeader: Story = {
  ...Template,
  args: {
    headers: tableHeaders,
    tableHeaderProps: {
      leftSectionChildren: <div>Custom Table</div>,
      tooltip: {
        tooltipContent: 'This is a custom table',
      },
    },
  },
}

export const NoSort: Story = {
  ...Template,
  args: {
    headers: tableHeaders,
    noSort: true,
  },
}
