import * as React from 'react'
import type { StoryFn, StoryObj, Meta } from '@storybook/react-webpack5'
import { Grid } from '.'
import type { Column, GridProps, GridActionsMenuFullProps } from '../../types'
import { GridCellDefault, GridCellDropdownMenu } from '../../components'
import {
    ButtonPrimary,
    EmptyState,
    ListItem,
    ListItemDivider,
    ListItemInfo,
    Menu,
} from '@planview/pv-uikit'
import { size } from '@planview/pv-utilities'
import { Copy, Cut, DotsVertical, Trash } from '@planview/pv-icons'

export default {
    title: 'pv-grid/Components/Grid',
    tags: ['autodocs'],
    component: Grid,
    parameters: {
        badges: ['intl'],
    },
    args: {
        rowHeight: 'medium',
        selectionMode: 'multi',
        filterMode: 'default',
        sortMode: 'internal',
    },
    argTypes: {
        loading: {
            control: { type: 'radio' },
            options: [false, true, 3, 6],
            table: {
                category: 'Status',
            },
        },
        emptyContent: {
            table: {
                category: 'Status',
            },
        },
        columns: {
            control: false,
        },
        columnGroups: {
            control: { type: 'radio' },
            options: ['without groups', 'with groups'],
            mapping: {
                'without groups': [],
                'with groups': [
                    {
                        id: 'top-group',
                        label: 'Group',
                        children: ['title', 'price'],
                    },
                ],
            },
        },
        rows: {
            control: false,
        },
        ref: {
            control: false,
            description:
                'This will return an api for interacting with the grid externally.',
            table: {
                category: 'Advanced',
            },
        },
        defaultSort: {
            control: false,
            table: {
                category: 'Sorting',
            },
        },
        sort: {
            control: false,
            table: {
                category: 'Sorting',
            },
        },
        sortMode: {
            table: {
                category: 'Sorting',
            },
        },
        multiColumnSort: {
            table: {
                category: 'Sorting',
            },
        },
        onSortChange: {
            table: {
                category: 'Sorting',
            },
        },
        selection: {
            table: {
                category: 'Selection',
            },
        },
        onSelectionChange: {
            table: {
                category: 'Selection',
            },
        },
        selectionMode: {
            table: {
                category: 'Selection',
            },
        },
        filter: {
            table: {
                category: 'Filtering',
            },
        },
        filterMode: {
            table: {
                category: 'Filtering',
            },
        },
        filteredIds: {
            control: { type: 'radio' },
            options: ['not filtered', 'filtered', 'no matches'],
            mapping: {
                'not filtered': undefined,
                filtered: ['1002'],
                'no matches': [],
            },
            table: {
                category: 'Filtering',
            },
        },
        preferencesAdapter: {
            control: false,
            table: {
                category: 'Advanced',
            },
        },
        expandedRows: {
            control: false,
            table: {
                category: 'Tree',
            },
        },
        onExpandedRowsChange: {
            table: {
                category: 'Tree',
            },
        },
        actionsMenu: {
            control: { type: 'radio' },
            options: ['no actions menu', 'actions menu', 'actions menu async'],
            mapping: {
                'no actions menu': undefined,
                'actions menu': () => (
                    <>
                        <ListItem icon={<Cut />} label="Cut" />
                        <ListItem icon={<Copy />} label="Copy" />
                        <ListItemDivider />
                        <ListItem icon={<Trash />} label="Delete" />
                    </>
                ),
                'actions menu async': {
                    Menu({ row, menuProps }: GridActionsMenuFullProps<Row>) {
                        const [loading, setLoading] = React.useState(true)

                        React.useEffect(() => {
                            const t = setTimeout(() => setLoading(false), 500)
                            return () => clearTimeout(t)
                        }, [])

                        return (
                            <Menu {...menuProps} loading={loading}>
                                <ListItemInfo>{row.title}</ListItemInfo>
                                <ListItemDivider />
                                <ListItem icon={<Cut />} label="Cut" />
                                <ListItem icon={<Copy />} label="Copy" />
                                <ListItemDivider />
                                <ListItem icon={<Trash />} label="Delete" />
                            </Menu>
                        )
                    },
                },
            },
            table: {
                category: 'Context Menu',
            },
        },
        enableColumnVisibilityMenu: {
            control: { type: 'boolean' },
            table: {
                category: 'Context Menu',
            },
        },
        rowDrag: {
            control: false,
            table: {
                category: 'Drag and Drop',
            },
        },
        onCellChange: {
            control: false,
            table: {
                category: 'Editing',
            },
        },
    },
} satisfies Meta<typeof Grid>

type Row = {
    id: string
    title: string
    price?: number
}

const rows = [
    { id: '1001', title: 'Journey to the Center of the Earth', price: 11.99 },
    {
        id: '1002',
        title: 'Twenty Thousand Leagues Under the Sea',
        price: 35.65,
    },
    { id: '1003', title: 'Around the World In Eighty Days', price: 29.98 },
]

const currencyFormatter = new Intl.NumberFormat(undefined, {
    style: 'currency',
    currency: 'USD',
})

export const Default: StoryFn<GridProps<Row>> = ({
    columns: _columns,
    rows: _rows,
    ...rest
}) => {
    const columns = React.useMemo<Column<Row>[]>(
        () => [
            {
                id: 'id',
                label: 'ID',
                width: 100,
            },
            {
                id: 'title',
                label: 'Title',
                width: 400,
            },
            {
                id: 'price',
                label: 'Price',
                width: 200,
                header: {
                    align: 'right',
                },
                cell: {
                    label: ({ value }: { value: number }) =>
                        currencyFormatter.format(value),
                    Renderer: ({ label, tabIndex }) => (
                        <GridCellDefault
                            numeric
                            tabIndex={tabIndex}
                            label={label}
                        />
                    ),
                },
            },
        ],
        []
    )

    return <Grid columns={columns} rows={rows} {...rest} />
}

Default.parameters = {
    docs: {
        source: {
            code: `
type Book = {
    id: number
    title: string
    price: number
}

const rows = React.useMemo<Book[]>(() => [
    { id: '1001', title: 'Journey to the Center of the Earth', price: 11.99 },
    {
        id: '1002',
        title: 'Twenty Thousand Leagues Under the Sea',
        price: 35.65,
    },
    { id: '1003', title: 'Around the World In Eighty Days', price: 29.98 },
], [])

const columns = React.useMemo<Column<Book>[]>(
    () => [
        {
            id: 'id',
            label: 'ID',
            width: 100,
        },
        {
            id: 'title',
            label: 'Title',
            width: 400,
        },
        {
            id: 'price',
            label: 'Price',
            width: 200,
            header: {
                align: 'right',
            },
            cell: {
                label: ({ value }: { value: number }) =>
                    currencyFormatter.format(value),
                Renderer: ({ label, tabIndex }) => (
                    <GridCellDefault numeric tabIndex={tabIndex} label={label} />
                ),
            },
        },
    ],
    []
)

return <Grid columns={columns} rows={rows} {...rest} />
            `,
        },
    },
}

export const LoadingState: StoryFn<GridProps<Row>> = ({
    columns: _columns,
    rows: _rows,
    ...rest
}) => {
    const columns = React.useMemo<Column<Row>[]>(
        () => [
            {
                id: 'id',
                label: 'ID',
                width: 100,
            },
            {
                id: 'title',
                label: 'Title',
                width: 400,
            },
            {
                id: 'price',
                label: 'Price',
                width: 200,
                header: {
                    align: 'right',
                },
                cell: {
                    label: ({ value }: { value: number }) =>
                        currencyFormatter.format(value),
                    Renderer: ({ label, tabIndex }) => (
                        <GridCellDefault
                            numeric
                            tabIndex={tabIndex}
                            label={label}
                        />
                    ),
                },
            },
        ],
        []
    )
    return <Grid columns={columns} rows={[]} {...rest} />
}

LoadingState.args = {
    loading: 3,
}

export const LocaleSorting: StoryObj<GridProps<Row>> = {
    args: {
        columns: [
            {
                id: 'title',
                label: 'Title (Natural sort)',
                sortStrategy: 'natural',
                width: 200,
            },
            {
                id: 'title-alt',
                label: 'Title (Fast sort)',
                cell: { value: ({ row }) => row.title },
                sortStrategy: 'fast',
                width: 200,
            },
        ],
        rows: [
            { id: '1', title: 'Alpha 20' },
            { id: '2', title: 'alpha 2' },
            { id: '3', title: 'alpha 100' },
            { id: '4', title: 'älpha 11' }, // spell-checker: disable-line
            { id: '5', title: 'Beta 99' },
        ],
        selectionMode: 'none',
        defaultSort: [{ columnId: 'title', direction: 'asc' }],
    },
}

export const StickyColumns: StoryObj<GridProps<Row>> = {
    args: {
        columns: [
            {
                id: 'id',
                label: 'ID',
                width: 100,
                sticky: 'left',
            },
            {
                id: 'title',
                label: 'Title',
                width: 400,
            },
            {
                id: 'desc',
                label: 'Description',
                width: 200,
                cell: {
                    value: () => 'N/A',
                },
            },
            {
                id: 'extra',
                label: 'Extra',
                width: 200,
                cell: {
                    value: () => 'N/A',
                },
            },
            {
                id: 'price',
                label: 'Price',
                width: 200,
                header: {
                    align: 'right',
                },
                cell: {
                    label: ({ value }: { value: number }) =>
                        currencyFormatter.format(value),
                    Renderer: ({ label, tabIndex }) => (
                        <GridCellDefault
                            numeric
                            tabIndex={tabIndex}
                            label={label}
                        />
                    ),
                },
            },
            {
                id: 'actions',
                label: '',
                width: size.small,
                resizable: false,
                movable: false,
                sortable: false,
                sticky: 'right',
                cell: {
                    Renderer({ tabIndex }) {
                        return (
                            <GridCellDropdownMenu
                                label="Actions menu"
                                tabIndex={tabIndex}
                                trigger={{ icon: <DotsVertical /> }}
                            >
                                <ListItem label="Perform an action" />
                            </GridCellDropdownMenu>
                        )
                    },
                },
            },
        ],
        rows,
    },
}

export const NoData: StoryObj<GridProps<Row>> = {
    args: {
        columns: [
            {
                id: 'id',
                label: 'ID',
                width: 100,
            },
            {
                id: 'title',
                label: 'Title',
                width: 400,
            },
            {
                id: 'price',
                label: 'Price',
                width: 200,
                header: {
                    align: 'right',
                },
            },
            {
                id: 'extra',
                label: 'Extra',
                width: 400,
            },
        ],
        rows: [],
        selectionMode: 'none',
        defaultSort: [{ columnId: 'title', direction: 'asc' }],
        emptyContent: (
            <EmptyState
                header="You have currently not identified any issues"
                illustration={
                    <img
                        width="291"
                        height="175"
                        src="img/empty/risk_issues_empty_state.svg"
                        alt="List of issues"
                    />
                }
                callToAction={<ButtonPrimary>Create Issue</ButtonPrimary>}
            />
        ),
    },
    decorators: [(Story) => <div style={{ height: 450 }}>{Story()}</div>],
}

export const ActionsMenu: StoryFn<GridProps<Row>> = ({
    columns: _columns,
    rows: _rows,
    ...rest
}) => {
    const columns = React.useMemo<Column<Row>[]>(
        () => [
            {
                id: 'id',
                label: 'ID',
                width: 100,
            },
            {
                id: 'title',
                label: 'Title',
                width: 400,
            },
            {
                id: 'price',
                label: 'Price',
                width: 200,
                header: {
                    align: 'right',
                },
                cell: {
                    label: ({ value }: { value: number }) =>
                        currencyFormatter.format(value),
                    Renderer: ({ label, tabIndex }) => (
                        <GridCellDefault
                            numeric
                            tabIndex={tabIndex}
                            label={label}
                        />
                    ),
                },
            },
        ],
        []
    )

    return <Grid columns={columns} rows={rows} {...rest} />
}

ActionsMenu.args = {
    actionsMenu: 'actions menu' as any,
}

ActionsMenu.parameters = {
    docs: {
        source: {
            code: `
<Grid
    columns={columns}
    rows={rows}
    actionsMenu={() => (
        <>
            <ListItem icon={<Cut />} label="Cut" />
            <ListItem icon={<Copy />} label="Copy" />
            <ListItemDivider />
            <ListItem icon={<Trash />} label="Delete" />
        </>
    )}
/>
            `,
        },
    },
}

ActionsMenu.tags = ['hidden']

export const ActionsMenuAsync: StoryFn<GridProps<Row>> = ({
    columns: _columns,
    rows: _rows,
    ...rest
}) => {
    const columns = React.useMemo<Column<Row>[]>(
        () => [
            {
                id: 'id',
                label: 'ID',
                width: 100,
            },
            {
                id: 'title',
                label: 'Title',
                width: 400,
            },
            {
                id: 'price',
                label: 'Price',
                width: 200,
                header: {
                    align: 'right',
                },
                cell: {
                    label: ({ value }: { value: number }) =>
                        currencyFormatter.format(value),
                    Renderer: ({ label, tabIndex }) => (
                        <GridCellDefault
                            numeric
                            tabIndex={tabIndex}
                            label={label}
                        />
                    ),
                },
            },
        ],
        []
    )

    return <Grid columns={columns} rows={rows} {...rest} />
}

ActionsMenuAsync.args = {
    actionsMenu: 'actions menu async' as any,
}

ActionsMenuAsync.parameters = {
    docs: {
        source: {
            code: `
<Grid
    columns={columns}
    rows={rows}
    actionsMenu={{
        Menu({ row, menuProps }: GridActionsMenuFullProps<Row>) {
            const [loading, setLoading] = React.useState(true)

            React.useEffect(() => {
                const t = setTimeout(() => setLoading(false), 500)
                return () => clearTimeout(t)
            }, [])

            return (
                <Menu {...menuProps} loading={loading}>
                    <ListItemInfo>{row.title}</ListItemInfo>
                    <ListItemDivider />
                    <ListItem icon={<Cut />} label="Cut" />
                    <ListItem icon={<Copy />} label="Copy" />
                    <ListItemDivider />
                    <ListItem icon={<Trash />} label="Delete" />
                </Menu>
            )
        },
    }}
/>
            `,
        },
    },
}

ActionsMenuAsync.tags = ['hidden']

export const Footer: StoryFn<GridProps<Row>> = ({
    columns: _columns,
    rows: _rows,
    ...rest
}) => {
    const columns = React.useMemo<Column<Row>[]>(
        () => [
            {
                id: 'id',
                label: 'ID',
                width: 100,
            },
            {
                id: 'title',
                label: 'Title',
                width: 400,
            },
            {
                id: 'price',
                label: 'Price',
                width: 200,
                header: {
                    align: 'right',
                },
                footer: {
                    aggregation: 'sum',
                    label: (value) =>
                        typeof value === 'number'
                            ? currencyFormatter.format(value)
                            : '',
                },
                cell: {
                    label: ({ value }: { value: number }) =>
                        currencyFormatter.format(value),
                    Renderer: ({ label, tabIndex }) => (
                        <GridCellDefault
                            numeric
                            tabIndex={tabIndex}
                            label={label}
                        />
                    ),
                },
            },
        ],
        []
    )

    return <Grid columns={columns} rows={rows} {...rest} />
}

Footer.tags = ['hidden']

export const ShowHideColumns: StoryFn<GridProps<Row>> = ({
    columns: _columns,
    rows: _rows,
    ...rest
}) => {
    const columns = React.useMemo<Column<Row>[]>(
        () => [
            {
                id: 'id',
                label: 'ID',
                width: 100,
                hideable: false,
            },
            {
                id: 'title',
                label: 'Title',
                width: 400,
            },
            {
                id: 'price',
                label: 'Price',
                width: 200,
                hidden: true,
                header: {
                    align: 'right',
                },
                cell: {
                    label: ({ value }: { value: number }) =>
                        currencyFormatter.format(value),
                    Renderer: ({ label, tabIndex }) => (
                        <GridCellDefault
                            numeric
                            tabIndex={tabIndex}
                            label={label}
                        />
                    ),
                },
            },
        ],
        []
    )

    return (
        <Grid
            enableColumnVisibilityMenu
            columns={columns}
            rows={rows}
            {...rest}
        />
    )
}

ShowHideColumns.tags = ['hidden']
