import { useRef, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { Route, BrowserRouter as Router, Routes } from 'react-router-dom';

import { Stack, Typography } from '@mui/material';
import { type Meta, type StoryObj } from '@storybook/react-vite';

import { useHuPagination } from '../../../hooks/useHuPagination';
import Checkbox from '../Checkbox/Checkbox';
import Skeleton from '../Skeleton';

import TableBody from './components/TableBody';
import TableCell from './components/TableCell';
import TableContainer from './components/TableContainer';
import TableHead from './components/TableHead';
import TableLoader from './components/TableLoader';
import TableRow from './components/TableRow';
import TableToolbar from './components/TableToolbar';
import Table from '.';

const rows = [
  {
    name: 'Frozen yoghurt',
    calories: 159,
    fat: 6.0,
    carbs: 24,
    protein: 4.0,
  },
  {
    name: 'Ice cream sandwich',
    calories: 237,
    fat: 9.0,
    carbs: 37,
    protein: 4.3,
  },
  {
    name: 'Eclair',
    calories: 262,
    fat: 16.0,
    carbs: 24,
    protein: 6.0,
  },
  {
    name: 'Cupcake',
    calories: 305,
    fat: 3.7,
    carbs: 67,
    protein: 4.3,
  },
  {
    name: 'Gingerbread',
    calories: 356,
    fat: 16.0,
    carbs: 49,
    protein: 3.9,
  },
  {
    name: 'Cheesecake',
    calories: 320,
    fat: 22.0,
    carbs: 25,
    protein: 5.0,
  },
  {
    name: 'Chocolate brownie',
    calories: 432,
    fat: 20.0,
    carbs: 52,
    protein: 5.0,
  },
  {
    name: 'Fruit tart',
    calories: 298,
    fat: 12.0,
    carbs: 41,
    protein: 2.8,
  },
  {
    name: 'Carrot cake',
    calories: 508,
    fat: 13.0,
    carbs: 61,
    protein: 1.8,
  },
];

const meta: Meta = {
  component: Table,
  title: 'Design System/Table',
  tags: ['autodocs'],
  argTypes: {},
  parameters: {
    docs: {
      source: {
        type: 'dynamic',
      },
    },
  },
};

export default meta;

type Story = StoryObj<typeof Table>;

export const Default: Story = {
  render: () => {
    return (
      <TableContainer>
        <Table sx={{ minWidth: 650 }}>
          <TableHead>
            <TableRow headerRow>
              <TableCell headerCell>Dessert</TableCell>
              <TableCell headerCell>Calories</TableCell>
              <TableCell headerCell>Fat&nbsp;(g)</TableCell>
              <TableCell headerCell>Carbs&nbsp;(g)</TableCell>
              <TableCell headerCell>Protein&nbsp;(g)</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {rows.map(row => (
              <TableRow key={row.name}>
                <TableCell
                  component="th"
                  scope="row"
                >
                  {row.name}
                </TableCell>
                <TableCell>{row.calories}</TableCell>
                <TableCell>{row.fat}</TableCell>
                <TableCell>{row.carbs}</TableCell>
                <TableCell>{row.protein}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
    );
  },
};

export const DefaultWithOnClick: Story = {
  render: () => {
    return (
      <TableContainer>
        <Table sx={{ minWidth: 650 }}>
          <TableHead>
            <TableRow headerRow>
              <TableCell headerCell>Dessert</TableCell>
              <TableCell headerCell>Calories</TableCell>
              <TableCell headerCell>Fat&nbsp;(g)</TableCell>
              <TableCell headerCell>Carbs&nbsp;(g)</TableCell>
              <TableCell headerCell>Protein&nbsp;(g)</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {rows.map(row => (
              <TableRow
                key={row.name}
                onClick={() => alert(row.name + ' clicked')}
              >
                <TableCell
                  component="th"
                  scope="row"
                >
                  {row.name}
                </TableCell>
                <TableCell>{row.calories}</TableCell>
                <TableCell>{row.fat}</TableCell>
                <TableCell>{row.carbs}</TableCell>
                <TableCell>{row.protein}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
    );
  },
};

export const SelectionTable: Story = {
  render: () => {
    const [selectedRows, setSelectedRows] = useState<number[]>([]);

    const handleSelection = (selectedIdx: number) => {
      setSelectedRows(prev => {
        if (prev.includes(selectedIdx)) {
          return prev.filter(idx => idx !== selectedIdx);
        }
        return [...prev, selectedIdx];
      });
    };

    const handleSelectAll = () => {
      if (selectedRows.length === rows.length) {
        setSelectedRows([]);
      } else {
        setSelectedRows(rows.map((_, idx) => idx));
      }
    };

    return (
      <TableContainer>
        <Table sx={{ minWidth: 650 }}>
          <TableHead>
            <TableRow headerRow>
              <TableCell
                headerCell
                selectionCell
              >
                <Checkbox
                  sx={{ zIndex: 100 }}
                  checked={selectedRows.length === rows.length}
                  onClick={handleSelectAll}
                />
              </TableCell>
              <TableCell
                headerCell
                tooltipTitle="Desert column"
              >
                Dessert
              </TableCell>

              <TableCell headerCell>Calories</TableCell>
              <TableCell headerCell>Fat&nbsp;(g)</TableCell>
              <TableCell headerCell>Carbs&nbsp;(g)</TableCell>
              <TableCell headerCell>Protein&nbsp;(g)</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {rows.map((row, index) => (
              <TableRow
                key={row.name}
                selected={selectedRows.includes(index)}
              >
                <TableCell selectionCell>
                  <Checkbox
                    sx={{ zIndex: 100 }}
                    disabled={false}
                    checked={selectedRows.includes(index)}
                    onClick={() => handleSelection(index)}
                  />
                </TableCell>
                <TableCell
                  component="th"
                  scope="row"
                >
                  {row.name}
                </TableCell>
                <TableCell>{row.calories}</TableCell>
                <TableCell>{row.fat}</TableCell>
                <TableCell>{row.carbs}</TableCell>
                <TableCell>{row.protein}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
    );
  },
};

export const CollapsableTable: Story = {
  render: () => {
    return (
      <TableContainer>
        <Table sx={{ minWidth: 650 }}>
          <TableHead>
            <TableRow headerRow>
              <TableCell
                headerCell
                collapsableCell
              ></TableCell>
              <TableCell
                headerCell
                tooltipTitle="Desert column"
              >
                Dessert
              </TableCell>

              <TableCell headerCell>Calories</TableCell>
              <TableCell headerCell>Fat&nbsp;(g)</TableCell>
              <TableCell headerCell>Carbs&nbsp;(g)</TableCell>
              <TableCell headerCell>Protein&nbsp;(g)</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {rows.map(row => (
              <TableRow
                key={row.name}
                collapsable
                renderDetail={detailRowProps => (
                  <TableRow {...detailRowProps}>
                    <TableCell />
                    <TableCell>{row.name}</TableCell>
                    <TableCell>{row.calories}</TableCell>
                    <TableCell>{row.fat}</TableCell>
                    <TableCell>{row.carbs}</TableCell>
                    <TableCell>{row.protein}</TableCell>
                  </TableRow>
                )}
              >
                <TableCell
                  component="th"
                  scope="row"
                >
                  {row.name}
                </TableCell>
                <TableCell>{row.calories}</TableCell>
                <TableCell>{row.fat}</TableCell>
                <TableCell>{row.carbs}</TableCell>
                <TableCell>{row.protein}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
    );
  },
};

export const Loading: Story = {
  render: () => {
    return (
      <TableContainer>
        <Table sx={{ minWidth: 650 }}>
          <TableHead>
            <TableRow headerRow>
              <TableCell headerCell>Dessert</TableCell>
              <TableCell headerCell>Calories</TableCell>
              <TableCell headerCell>Fat&nbsp;(g)</TableCell>
              <TableCell headerCell>Carbs&nbsp;(g)</TableCell>
              <TableCell headerCell>Protein&nbsp;(g)</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {rows.map(row => (
              <TableRow key={row.name}>
                <TableCell
                  component="th"
                  scope="row"
                >
                  <Skeleton
                    isLoading
                    width={98}
                    height={33}
                    variant="rounded"
                  />
                </TableCell>
                <TableCell
                  component="th"
                  scope="row"
                >
                  <Skeleton
                    isLoading
                    width={98}
                    height={33}
                    variant="rounded"
                  />
                </TableCell>
                <TableCell
                  component="th"
                  scope="row"
                >
                  <Skeleton
                    isLoading
                    width={98}
                    height={33}
                    variant="rounded"
                  />
                </TableCell>
                <TableCell
                  component="th"
                  scope="row"
                >
                  <Skeleton
                    isLoading
                    width={98}
                    height={33}
                    variant="rounded"
                  />
                </TableCell>
                <TableCell
                  component="th"
                  scope="row"
                >
                  <Skeleton
                    isLoading
                    width={98}
                    height={33}
                    variant="rounded"
                  />
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
    );
  },
};

export const ActionsMenu: Story = {
  render: () => {
    return (
      <TableContainer>
        <Table sx={{ minWidth: 650 }}>
          <TableHead>
            <TableRow headerRow>
              <TableCell headerCell>Dessert</TableCell>
              <TableCell headerCell>Calories</TableCell>
              <TableCell headerCell>Fat&nbsp;(g)</TableCell>
              <TableCell headerCell>Carbs&nbsp;(g)</TableCell>
              <TableCell headerCell>Protein&nbsp;(g)</TableCell>
              <TableCell aria-label={'actions'} />
            </TableRow>
          </TableHead>
          <TableBody>
            {rows.map(row => (
              <TableRow key={row.name}>
                <TableCell
                  component="th"
                  scope="row"
                >
                  {row.name}
                </TableCell>
                <TableCell>{row.calories}</TableCell>
                <TableCell>{row.fat}</TableCell>
                <TableCell>{row.carbs}</TableCell>
                <TableCell>{row.protein}</TableCell>
                <TableCell
                  variant="shortField"
                  align="right"
                  sx={{
                    whiteSpace: 'nowrap',
                  }}
                ></TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
    );
  },
};

export const Toolbar: Story = {
  render: () => {
    const [selectedRows, setSelectedRows] = useState<number[]>([]);

    const handleSelection = (selectedIdx: number) => {
      setSelectedRows(prev => {
        if (prev.includes(selectedIdx)) {
          return prev.filter(idx => idx !== selectedIdx);
        }
        return [...prev, selectedIdx];
      });
    };

    const handleSelectAll = () => {
      if (selectedRows.length === rows.length) {
        setSelectedRows([]);
      } else {
        setSelectedRows(rows.map((_, idx) => idx));
      }
    };

    return (
      <TableContainer>
        <TableToolbar>
          <Typography variant="globalS">{`Selected rows: ${selectedRows.length}`}</Typography>
        </TableToolbar>
        <Table sx={{ minWidth: 650 }}>
          <TableHead>
            <TableRow headerRow>
              <TableCell
                headerCell
                selectionCell
              >
                <Checkbox
                  checked={selectedRows.length === rows.length}
                  onClick={e => {
                    e.stopPropagation();
                    handleSelectAll();
                  }}
                />
              </TableCell>
              <TableCell
                headerCell
                tooltipTitle="Desert column"
              >
                Dessert
              </TableCell>
              <TableCell headerCell>Calories</TableCell>
              <TableCell headerCell>Fat&nbsp;(g)</TableCell>
              <TableCell headerCell>Carbs&nbsp;(g)</TableCell>
              <TableCell headerCell>Protein&nbsp;(g)</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {rows.map((row, index) => (
              <TableRow
                key={row.name}
                selected={selectedRows.includes(index)}
              >
                <TableCell selectionCell>
                  <Checkbox
                    sx={{ zIndex: 100 }}
                    disabled={false}
                    checked={selectedRows.includes(index)}
                    onClick={() => handleSelection(index)}
                  />
                </TableCell>
                <TableCell
                  component="th"
                  scope="row"
                >
                  {row.name}
                </TableCell>
                <TableCell>{row.calories}</TableCell>
                <TableCell>{row.fat}</TableCell>
                <TableCell>{row.carbs}</TableCell>
                <TableCell>{row.protein}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
    );
  },
};

export const Tooltips: Story = {
  render: () => {
    return (
      <TableContainer>
        <Table sx={{ minWidth: 650 }}>
          <TableHead>
            <TableRow headerRow>
              <TableCell
                headerCell
                tooltipTitle="Dessert column"
              >
                Dessert
              </TableCell>
              <TableCell
                headerCell
                tooltipTitle="Calories column"
              >
                Calories
              </TableCell>
              <TableCell
                headerCell
                tooltipTitle={'Fat column'}
              >
                Fat&nbsp;(g)
              </TableCell>
              <TableCell
                headerCell
                tooltipTitle={'Carbohydrates column'}
              >
                Carbs&nbsp;(g)
              </TableCell>
              <TableCell
                headerCell
                tooltipTitle={'Protein column'}
              >
                Protein&nbsp;(g)
              </TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {rows.map(row => (
              <TableRow key={row.name}>
                <TableCell
                  tooltipTitle="Content"
                  component="th"
                  align="left"
                >
                  <Content />
                </TableCell>
                <TableCell
                  tooltipTitle={'Amount of calories per serving'}
                  align="center"
                >
                  {row.calories}
                </TableCell>
                <TableCell
                  align="center"
                  tooltipTitle={'Amount of fat per serving'}
                >
                  {row.fat}
                </TableCell>
                <TableCell
                  align="center"
                  tooltipTitle={'Amount of carbohydrates per serving'}
                >
                  {row.carbs}
                </TableCell>
                <TableCell
                  align="center"
                  tooltipTitle={'Amount of protein per serving'}
                >
                  {row.protein}
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
    );
  },
};

const Content = () => (
  <Stack
    sx={{
      width: 1,
      height: '33px',
      border: '1px dashed #CAD5FE',
      backgroundColor: '#EFF2FF',
      borderRadius: '8px',
    }}
  />
);

export const InfiniteScrolling: Story = {
  render: () => {
    // Initial data set (first page)
    const [desserts, setDesserts] = useState(rows.slice(0, 3));
    const [loading, setLoading] = useState(false);
    const [page, setPage] = useState(1);
    const pageRef = useRef<HTMLDivElement>(null);
    const totalItems = rows.length;

    // Simulate a service call to load more data
    const loadMoreData = async () => {
      setLoading(true);

      // Simulate API delay
      await new Promise(resolve => setTimeout(resolve, 1500));

      // Calculate next items to load
      const startIndex = page * 3;
      const endIndex = Math.min(startIndex + 3, rows.length);
      const hasMoreItems = rows[startIndex] !== undefined;

      if (hasMoreItems) {
        // Add new items
        setDesserts(prev => [...prev, ...rows.slice(startIndex, endIndex)]);
        setPage(page + 1);
      }

      setLoading(false);
    };

    const scrollToTop = () => {
      if (pageRef.current) {
        pageRef.current.scrollTo({
          top: 0,
          behavior: 'smooth',
        });
      }
    };

    return (
      <Stack
        ref={pageRef}
        sx={{
          gap: 1,
          maxHeight: '400px',
          padding: 4,
          overflowY: 'auto',
        }}
      >
        <TableContainer sx={{ boxSizing: 'border-box', flex: '1 0 auto' }}>
          <Table>
            <TableHead>
              <TableRow headerRow>
                <TableCell headerCell>Dessert</TableCell>
                <TableCell headerCell>Calories</TableCell>
                <TableCell headerCell>Fat&nbsp;(g)</TableCell>
                <TableCell headerCell>Carbs&nbsp;(g)</TableCell>
                <TableCell headerCell>Protein&nbsp;(g)</TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {desserts.map(row => (
                <TableRow key={row.name}>
                  <TableCell
                    component="th"
                    scope="row"
                  >
                    {row.name}
                  </TableCell>
                  <TableCell>{row.calories}</TableCell>
                  <TableCell>{row.fat}</TableCell>
                  <TableCell>{row.carbs}</TableCell>
                  <TableCell>{row.protein}</TableCell>
                </TableRow>
              ))}

              {loading && (
                <TableRow>
                  {[...Array(5)].map((_, index) => (
                    <TableCell key={index}>
                      <Skeleton
                        isLoading
                        width="100%"
                        height={33}
                        variant="rounded"
                      />
                    </TableCell>
                  ))}
                </TableRow>
              )}
            </TableBody>
          </Table>
        </TableContainer>
        <TableLoader
          loadedCount={desserts.length}
          totalCount={totalItems}
          onLoadMore={loadMoreData}
          onScrollToTop={scrollToTop}
        />
      </Stack>
    );
  },
};

export const Sorting: Story = {
  render: () => {
    return (
      <Router>
        <Routes>
          <Route
            path="*"
            element={<SortingContent />}
          />
        </Routes>
      </Router>
    );
  },
};

const SortingContent = () => {
  const { HuTableSortingHeader, params } = useHuPagination({
    defaultOrder: 'ASC',
    defaultOrderBy: 'NAME',
  });
  const { order, orderBy } = params;
  const sortedRows = [...rows].sort((a, b) => {
    const getValue = (row: (typeof rows)[0], key: string) => {
      const value = row[key.toLowerCase() as keyof typeof row];
      return typeof value === 'string' ? value.toLowerCase() : value;
    };

    const aValue = getValue(a, orderBy);
    const bValue = getValue(b, orderBy);
    if (order === 'ASC') {
      if (aValue < bValue) return -1;
      if (aValue > bValue) return 1;
      return 0;
    } else if (order === 'DESC_NULLS_LAST') {
      if (bValue < aValue) return -1;
      if (bValue > aValue) return 1;
      return 0;
    }
    return 0;
  });

  return (
    <TableContainer sx={{ boxSizing: 'border-box', flex: '1 0 auto' }}>
      <Table>
        <TableHead>
          <TableRow headerRow>
            <HuTableSortingHeader id="NAME">Dessert</HuTableSortingHeader>
            <HuTableSortingHeader id="CALORIES">Calories</HuTableSortingHeader>
            <HuTableSortingHeader id="FAT">Fat&nbsp;(g)</HuTableSortingHeader>
            <HuTableSortingHeader id="CARBS">
              Carbs&nbsp;(g)
            </HuTableSortingHeader>
            <HuTableSortingHeader id="PROTEIN">
              Protein&nbsp;(g)
            </HuTableSortingHeader>
          </TableRow>
        </TableHead>
        <TableBody>
          {sortedRows.map(row => (
            <TableRow key={row.name}>
              <TableCell
                component="th"
                scope="row"
              >
                {row.name}
              </TableCell>
              <TableCell>{row.calories}</TableCell>
              <TableCell>{row.fat}</TableCell>
              <TableCell>{row.carbs}</TableCell>
              <TableCell>{row.protein}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
};

export const SortingWithTooltip: Story = {
  render: () => {
    return (
      <Router>
        <Routes>
          <Route
            path="*"
            element={<SortingWithTooltipContent />}
          />
        </Routes>
      </Router>
    );
  },
};

const SortingWithTooltipContent = () => {
  const form = useForm();

  const { HuTableSortingHeader, params } = useHuPagination({
    defaultOrder: 'ASC',
    defaultOrderBy: 'NAME',
  });

  const { order, orderBy } = params;

  const sortedRows = [...rows].sort((a, b) => {
    const getValue = (row: (typeof rows)[0], key: string) => {
      const value = row[key.toLowerCase() as keyof typeof row];
      return typeof value === 'string' ? value.toLowerCase() : value;
    };

    const aValue = getValue(a, orderBy);
    const bValue = getValue(b, orderBy);
    if (order === 'ASC') {
      if (aValue < bValue) return -1;
      if (aValue > bValue) return 1;
      return 0;
    } else if (order === 'DESC_NULLS_LAST') {
      if (bValue < aValue) return -1;
      if (bValue > aValue) return 1;
      return 0;
    }
    return 0;
  });

  const getTooltipTitle = (property: string) => {
    if (orderBy === property) {
      if (order === 'ASC') {
        return 'Sorted by 0 to 100';
      } else if (order === 'DESC_NULLS_LAST') {
        return 'Sorted by 100 to 0';
      }
    }
    return 'Sort by';
  };

  return (
    <TableContainer sx={{ boxSizing: 'border-box', flex: '1 0 auto' }}>
      <Table>
        <TableHead>
          <FormProvider {...form}>
            <TableRow headerRow>
              <HuTableSortingHeader id="NAME">Dessert</HuTableSortingHeader>
              <HuTableSortingHeader
                id="CALORIES"
                tooltipTitle=""
              >
                Calories
              </HuTableSortingHeader>
              <HuTableSortingHeader
                id="FAT"
                tooltipTitle={getTooltipTitle('FAT')}
              >
                Fat&nbsp;(g)
              </HuTableSortingHeader>
              <HuTableSortingHeader
                id="CARBS"
                tooltipTitle=""
              >
                Carbs&nbsp;(g)
              </HuTableSortingHeader>
              <HuTableSortingHeader
                id="PROTEIN"
                tooltipTitle=""
              >
                Protein&nbsp;(g)
              </HuTableSortingHeader>
            </TableRow>
          </FormProvider>
        </TableHead>
        <TableBody>
          {sortedRows.map(row => (
            <TableRow key={row.name}>
              <TableCell
                component="th"
                scope="row"
              >
                {row.name}
              </TableCell>
              <TableCell>{row.calories}</TableCell>
              <TableCell>{row.fat}</TableCell>
              <TableCell>{row.carbs}</TableCell>
              <TableCell>{row.protein}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  );
};
