import type { Meta, StoryObj } from '@storybook/react'
import { useState, useEffect } from 'react'
import { Tag } from '../Tag'
import { Typography } from '../Typography'
import {
  DataTable,
  type DataTableColumn,
  type PaginationConfig,
} from './DataTable'

type OracleResponse = {
  oracle: string
  value: string
  timestamp: string
}

const oracleData: OracleResponse[] = [
  {
    oracle: 'Fiews',
    value: '22.1',
    timestamp: 'January 01, 14:52',
  },
  {
    oracle: 'Chainlayer',
    value: '22.551',
    timestamp: 'January 01, 14:53',
  },
  {
    oracle: 'LinkPool',
    value: '22.612348',
    timestamp: 'January 01, 14:54',
  },
  {
    oracle: 'Omniscience',
    value: '22.50',
    timestamp: 'January 01, 14:54',
  },
  {
    oracle: 'P2P.org',
    value: '23.1247',
    timestamp: 'January 01, 14:54',
  },
]

type DefaultResponse = {
  text: string
  code: string
  tag: string
}

const defaultData: DefaultResponse[] = [
  {
    text: 'Sample Text',
    code: 'SAMPLE_CODE',
    tag: 'Default',
  },
  {
    text: 'Another Text',
    code: 'ANOTHER_CODE',
    tag: 'Success',
  },
  {
    text: 'More Text',
    code: 'MORE_CODE',
    tag: 'Warning',
  },
]

const defaultColumns: DataTableColumn<DefaultResponse>[] = [
  {
    accessorKey: 'text',
    header: 'Text',
    cell: ({ row }) => (
      <Typography variant="body-s">{row.getValue('text')}</Typography>
    ),
    meta: { skeletonWidth: 80 },
  },
  {
    accessorKey: 'code',
    header: 'Code',
    cell: ({ row }) => (
      <Typography variant="code">{row.getValue('code')}</Typography>
    ),
    meta: { skeletonWidth: 120 },
  },
  {
    accessorKey: 'tag',
    header: 'Tag',
    cell: ({ row }) => {
      const tagValue = (row.getValue('tag') as string).toLowerCase()
      return (
        <Tag
          variant={
            tagValue === 'success'
              ? 'success'
              : tagValue === 'warning'
                ? 'warning'
                : 'default'
          }
        >
          {row.getValue('tag')}
        </Tag>
      )
    },
    meta: { skeletonWidth: 64 },
  },
]

const oracleColumns: DataTableColumn<OracleResponse>[] = [
  {
    accessorKey: 'oracle',
    header: 'Name',
    enableSorting: true,
    meta: { skeletonWidth: 100 },
  },
  {
    accessorKey: 'value',
    header: 'Latest answer',
    enableSorting: false,
    meta: { skeletonWidth: 80 },
  },
  {
    accessorKey: 'timestamp',
    header: 'Last updated',
    enableSorting: false,
    meta: { skeletonWidth: 150 },
  },
]

type TokenResponse = {
  symbol: string
  name: string
  price: string
}

const tokenData: TokenResponse[] = [
  {
    symbol: 'BTC',
    name: 'Bitcoin',
    price: '$43,250.75',
  },
  {
    symbol: 'ETH',
    name: 'Ethereum',
    price: '$2,680.45',
  },
  {
    symbol: 'SOL',
    name: 'Solana',
    price: '$98.32',
  },
  {
    symbol: 'XRP',
    name: 'Ripple',
    price: '$0.62',
  },
  {
    symbol: 'AVAX',
    name: 'Avalanche',
    price: '$34.56',
  },
  {
    symbol: 'MATIC',
    name: 'Polygon',
    price: '$0.89',
  },
  {
    symbol: 'ADA',
    name: 'Cardano',
    price: '$0.52',
  },
  {
    symbol: 'DOT',
    name: 'Polkadot',
    price: '$7.23',
  },
  {
    symbol: 'LINK',
    name: 'Chainlink',
    price: '$15.67',
  },
  {
    symbol: 'UNI',
    name: 'Uniswap',
    price: '$8.45',
  },
  {
    symbol: 'ATOM',
    name: 'Cosmos',
    price: '$9.12',
  },
  {
    symbol: 'LTC',
    name: 'Litecoin',
    price: '$72.34',
  },
  {
    symbol: 'BCH',
    name: 'Bitcoin Cash',
    price: '$245.67',
  },
  {
    symbol: 'XLM',
    name: 'Stellar',
    price: '$0.13',
  },
  {
    symbol: 'VET',
    name: 'VeChain',
    price: '$0.028',
  },
  {
    symbol: 'FIL',
    name: 'Filecoin',
    price: '$5.89',
  },
  {
    symbol: 'TRX',
    name: 'TRON',
    price: '$0.087',
  },
  {
    symbol: 'ETC',
    name: 'Ethereum Classic',
    price: '$23.45',
  },
  {
    symbol: 'XMR',
    name: 'Monero',
    price: '$165.78',
  },
  {
    symbol: 'EOS',
    name: 'EOS',
    price: '$0.76',
  },
  {
    symbol: 'AAVE',
    name: 'Aave',
    price: '$89.23',
  },
  {
    symbol: 'ALGO',
    name: 'Algorand',
    price: '$0.18',
  },
]

const tokenColumns: DataTableColumn<TokenResponse>[] = [
  {
    accessorKey: 'symbol',
    header: 'Symbol',
    enableSorting: true,
    cell: ({ row }) => (
      <Typography variant="body-s" className="font-semibold">
        {row.getValue('symbol')}
      </Typography>
    ),
    meta: { skeletonWidth: 80 },
  },
  {
    accessorKey: 'name',
    header: 'Name',
    enableSorting: true,
    cell: ({ row }) => (
      <Typography variant="body-s">{row.getValue('name')}</Typography>
    ),
    meta: { skeletonWidth: 120 },
  },
  {
    accessorKey: 'price',
    header: 'Price',
    enableSorting: true,
    cell: ({ row }) => (
      <Typography variant="body-s">{row.getValue('price')}</Typography>
    ),
    meta: { skeletonWidth: 100 },
  },
]

const meta: Meta<typeof DataTable> = {
  component: DataTable,
  title: 'Blocks/Table/DataTable',
  parameters: {
    layout: 'padded',
    docs: {
      source: { type: 'code' },
    },
  },
  argTypes: {
    data: {
      control: 'object',
      description: 'The data to be displayed in the table',
    },
    columns: {
      control: 'object',
      description: 'The column definitions for the table',
    },
    isLoading: {
      control: 'boolean',
      description: 'Whether the table is in a loading state',
    },
    tableOptions: {
      control: false,
      description:
        'TanStack Table configuration options. Check [TanStack Table Documentation](https://tanstack.com/table/latest/docs/api/core/table).',
      table: {
        type: { summary: 'TableOptions' },
      },
    },
  },
}
export default meta

type Story<T> = StoryObj<typeof DataTable<T, unknown>>

export const Default: Story<DefaultResponse> = {
  args: {
    columns: defaultColumns,
    data: defaultData,
    isLoading: false,
  },
}

export const Loading: Story<DefaultResponse> = {
  args: {
    columns: defaultColumns,
    data: defaultData,
    isLoading: true,
  },
}

export const LoadingDefault: Story<DefaultResponse> = {
  args: {
    columns: defaultColumns,
    data: [],
    isLoading: true,
  },
}

export const LoadingWithPlaceholdersFromPagination: Story<DefaultResponse> = {
  args: {
    columns: defaultColumns,
    data: [],
    isLoading: true,
    pagination: {
      pageSize: 7,
    },
  },
}

export const LoadingWithCustomPlaceholderCount: Story<DefaultResponse> = {
  args: {
    columns: defaultColumns,
    data: [],
    isLoading: true,
    placeholderCount: 3,
  },
}

export const Empty: Story<DefaultResponse> = {
  args: {
    columns: defaultColumns,
    data: [],
    isLoading: false,
  },
}

export const OracleTableExample: Story<OracleResponse> = {
  args: {
    columns: oracleColumns,
    data: oracleData,
    isLoading: false,
  },
}

export const WithPagination: Story<TokenResponse> = {
  args: {
    columns: tokenColumns,
    data: tokenData,
    isLoading: false,
  },
}

export const WithCustomPagination: Story<OracleResponse> = {
  args: {
    columns: oracleColumns,
    data: oracleData,
    isLoading: false,
    pagination: {
      pageSize: 3,
    },
  },
}

export const WithSelectPagination: Story<OracleResponse> = {
  args: {
    columns: oracleColumns,
    data: oracleData,
    isLoading: false,
    pagination: {
      pageSize: 3,
      pageControlMode: 'select',
    },
  },
}

export const WithDisplayPagination: Story<OracleResponse> = {
  args: {
    columns: oracleColumns,
    data: oracleData,
    isLoading: false,
    pagination: {
      pageSize: 3,
      pageControlMode: 'display',
      showPaginationDisplay: false,
    },
  },
}

// Server-side pagination example
type UserData = {
  id: string
  name: string
  email: string
  role: string
  status: 'active' | 'inactive' | 'pending'
}

// Mock API function that simulates server-side pagination
const mockApiCall = async (
  pageIndex: number,
  pageSize: number,
): Promise<{
  data: UserData[]
  totalCount: number
}> => {
  // Simulate network delay
  await new Promise((resolve) => setTimeout(resolve, 500))

  // Generate mock data
  const allData: UserData[] = Array.from({ length: 150 }, (_, i) => ({
    id: `user-${i + 1}`,
    name: `User ${i + 1}`,
    email: `user${i + 1}@example.com`,
    role: ['Admin', 'User', 'Moderator', 'Guest'][i % 4],
    status: ['active', 'inactive', 'pending'][i % 3] as
      | 'active'
      | 'inactive'
      | 'pending',
  }))

  const startIndex = pageIndex * pageSize
  const endIndex = startIndex + pageSize
  const data = allData.slice(startIndex, endIndex)

  return {
    data,
    totalCount: allData.length,
  }
}

const mockApiCallWithoutTotal = async (
  pageIndex: number,
  pageSize: number,
): Promise<{
  data: UserData[]
  hasMore: boolean
}> => {
  await new Promise((resolve) => setTimeout(resolve, 500))

  const allData: UserData[] = Array.from({ length: 47 }, (_, i) => ({
    id: `user-${i + 1}`,
    name: `User ${i + 1}`,
    email: `user${i + 1}@example.com`,
    role: ['Admin', 'User', 'Moderator', 'Guest'][i % 4],
    status: ['active', 'inactive', 'pending'][i % 3] as
      | 'active'
      | 'inactive'
      | 'pending',
  }))

  const startIndex = pageIndex * pageSize
  const endIndex = startIndex + pageSize
  const data = allData.slice(startIndex, endIndex)

  return {
    data,
    hasMore: endIndex < allData.length,
  }
}

const userColumns: DataTableColumn<UserData>[] = [
  {
    accessorKey: 'name',
    header: 'Name',
    enableSorting: true,
    cell: ({ row }) => (
      <Typography variant="body-s" className="font-medium">
        {row.getValue('name')}
      </Typography>
    ),
    meta: { skeletonWidth: 120 },
  },
  {
    accessorKey: 'email',
    header: 'Email',
    enableSorting: true,
    cell: ({ row }) => (
      <Typography variant="body-s">{row.getValue('email')}</Typography>
    ),
    meta: { skeletonWidth: 200 },
  },
  {
    accessorKey: 'role',
    header: 'Role',
    enableSorting: true,
    cell: ({ row }) => (
      <Typography variant="body-s">{row.getValue('role')}</Typography>
    ),
    meta: { skeletonWidth: 100 },
  },
  {
    accessorKey: 'status',
    header: 'Status',
    enableSorting: true,
    cell: ({ row }) => {
      const status = row.getValue('status') as string
      return (
        <Tag
          variant={
            status === 'active'
              ? 'success'
              : status === 'inactive'
                ? 'urgent'
                : 'warning'
          }
        >
          {status}
        </Tag>
      )
    },
    meta: { skeletonWidth: 80 },
  },
]

const ServerSidePaginationComponent = () => {
  const [data, setData] = useState<UserData[]>([])
  const [isLoading, setIsLoading] = useState(false)
  const [totalCount, setTotalCount] = useState(0)

  const fetchData = async (pageIndex: number, pageSize: number) => {
    setIsLoading(true)
    try {
      const result = await mockApiCall(pageIndex, pageSize)
      setData(result.data)
      setTotalCount(result.totalCount)
    } catch (error) {
      console.error('Failed to fetch data:', error)
    } finally {
      setIsLoading(false)
    }
  }

  const paginationConfig: PaginationConfig = {
    pageSize: 10,
    serverSide: true,
    totalCount,
    onPageChange: fetchData,
  }

  // Initial data fetch
  useEffect(() => {
    void fetchData(0, 10)
  }, [])

  return (
    <DataTable
      columns={userColumns}
      data={data}
      isLoading={isLoading}
      pagination={paginationConfig}
    />
  )
}

export const ServerSidePagination: Story<UserData> = {
  render: () => <ServerSidePaginationComponent />,
  parameters: {
    docs: {
      source: {
        code: `const paginationConfig: PaginationConfig = {
  pageSize: 10,
  serverSide: true,
  totalCount,
  onPageChange: fetchData,
}

<DataTable
  columns={userColumns}
  data={data}
  isLoading={isLoading}
  pagination={paginationConfig}
/>`,
      },
    },
  },
}

const ServerSidePaginationWithoutTotalComponent = () => {
  const [data, setData] = useState<UserData[]>([])
  const [isLoading, setIsLoading] = useState(false)
  const [pageIndex, setPageIndex] = useState(0)
  const [hasMore, setHasMore] = useState(false)
  const pageSize = 10

  const fetchData = async (nextPageIndex: number, nextPageSize: number) => {
    setIsLoading(true)
    try {
      const result = await mockApiCallWithoutTotal(nextPageIndex, nextPageSize)
      setData(result.data)
      setPageIndex(nextPageIndex)
      setHasMore(result.hasMore)
    } catch (error) {
      console.error('Failed to fetch data:', error)
    } finally {
      setIsLoading(false)
    }
  }

  const paginationConfig: PaginationConfig = {
    pageIndex,
    pageSize,
    serverSide: true,
    currentPageCount: data.length,
    canNextPage: hasMore,
    onPageChange: fetchData,
  }

  useEffect(() => {
    void fetchData(0, pageSize)
  }, [])

  return (
    <DataTable
      columns={userColumns}
      data={data}
      isLoading={isLoading}
      pagination={paginationConfig}
    />
  )
}

const ServerSidePaginationWithoutTotalDisplayComponent = () => {
  const [data, setData] = useState<UserData[]>([])
  const [isLoading, setIsLoading] = useState(false)
  const [pageIndex, setPageIndex] = useState(0)
  const [hasMore, setHasMore] = useState(false)
  const pageSize = 10

  const fetchData = async (nextPageIndex: number, nextPageSize: number) => {
    setIsLoading(true)
    try {
      const result = await mockApiCallWithoutTotal(nextPageIndex, nextPageSize)
      setData(result.data)
      setPageIndex(nextPageIndex)
      setHasMore(result.hasMore)
    } catch (error) {
      console.error('Failed to fetch data:', error)
    } finally {
      setIsLoading(false)
    }
  }

  const paginationConfig: PaginationConfig = {
    pageIndex,
    pageSize,
    serverSide: true,
    currentPageCount: data.length,
    canNextPage: hasMore,
    onPageChange: fetchData,
    pageControlMode: 'display',
    showPaginationDisplay: false,
  }

  useEffect(() => {
    void fetchData(0, pageSize)
  }, [])

  return (
    <DataTable
      columns={userColumns}
      data={data}
      isLoading={isLoading}
      pagination={paginationConfig}
    />
  )
}

export const ServerSidePaginationWithoutTotal: Story<UserData> = {
  render: () => <ServerSidePaginationWithoutTotalComponent />,
  parameters: {
    docs: {
      source: {
        code: `const paginationConfig: PaginationConfig = {
  pageIndex,
  pageSize: 10,
  serverSide: true,
  currentPageCount: data.length,
  canNextPage: hasMore,
  onPageChange: fetchData,
}

<DataTable
  columns={userColumns}
  data={data}
  isLoading={isLoading}
  pagination={paginationConfig}
/>`,
      },
    },
  },
}

export const ServerSidePaginationWithoutTotalDisplay: Story<UserData> = {
  render: () => <ServerSidePaginationWithoutTotalDisplayComponent />,
  parameters: {
    docs: {
      source: {
        code: `const paginationConfig: PaginationConfig = {
  pageIndex,
  pageSize: 10,
  serverSide: true,
  currentPageCount: data.length,
  canNextPage: hasMore,
  onPageChange: fetchData,
  pageControlMode: 'display',
  showPaginationDisplay: false,
}

<DataTable
  columns={userColumns}
  data={data}
  isLoading={isLoading}
  pagination={paginationConfig}
/>`,
      },
    },
  },
}
