import React, { useEffect, useState, type FC, type ReactNode } from 'react';
import {
    Alert,
    GridTable,
    Status,
    Tab,
    Tabs,
    type GridTableRowInstance,
    type GridTableSortBy,
} from '@theorchard/suite-components';
import { useGetMetadataReportQuery } from 'src/data/queries/getMetadataErrorReport';
import './index.scss';
import JSONableProductErrorReport from './productErrorReport';
import JSONableProjectErrorReport from './projectErrorReport';
import {
    type Product,
    type Project,
    type EntityType,
    BulkSessionSortBy,
    mapToSortBy,
    OrderDir,
} from './types';
import type { ColumnDefinition } from '@theorchard/suite-components/dist/esm/src/components/table/base/types';

interface TableProps<T extends EntityType> {
    loading: boolean;
    entities: T[] | null;
    columnDefs: ColumnDefinition<T>[];
    page: number;
    pageSize: number;
    totalEntityCount: number;
    hasErrors: (entity: T) => boolean;
    renderErrorReport: (entity: T) => ReactNode;
    onPageChange: (page: number) => void;
    onPageSizeChange: (pageSize: number) => void;
    onSortChange?: (sortBy: string, sortOrder: OrderDir) => void;
}

export const MetadataErrorReportTable = <T extends EntityType>({
    loading,
    entities,
    columnDefs,
    page,
    pageSize,
    totalEntityCount,
    hasErrors,
    renderErrorReport,
    onPageChange,
    onPageSizeChange,
    onSortChange,
}: TableProps<T>) => {
    const [expandedRows, setExpandedRows] = useState<Record<string, FC>>({});

    useEffect(() => {
        setExpandedRows({});
    }, [renderErrorReport]);

    const data = entities?.map((entity, idx) => ({
        ...entity,
        key: `${String(entity.name ?? 'entity')}-${idx}`,
        status: hasErrors(entity),
    }));

    const columnDefsWithStatus = [
        ...columnDefs,
        {
            name: 'status',
            title: $t(
                'bulkDigitalAudio.metadataErrorReport.tableHeaders.status'
            ),
            sortable: true,

            Cell: ({ data }: { data: T }) => (
                <Status
                    text={
                        hasErrors(data)
                            ? $t(
                                  'bulkDigitalAudio.metadataErrorReport.status.failed'
                              )
                            : $t(
                                  'bulkDigitalAudio.metadataErrorReport.status.success'
                              )
                    }
                    variant={hasErrors(data) ? 'error' : 'success'}
                    filled={true}
                />
            ),
        },
    ];

    return (
        <GridTable
            variant="zebra"
            loading={loading}
            bordered={true}
            className="error-report-table"
            data={data}
            onRowClick={props => {
                const { key }: GridTableRowInstance<T> = props;
                const entity = data?.find(entity => entity.key === key);
                if (expandedRows[key]) {
                    setExpandedRows({});
                } else {
                    const newExpandedRows = {
                        [key]: () =>
                            entity ? renderErrorReport(entity) : null,
                    } as Record<string, FC>;
                    setExpandedRows(newExpandedRows);
                }
            }}
            onSort={
                onSortChange
                    ? (sortByArray: GridTableSortBy[]) => {
                          if (sortByArray && sortByArray.length > 0) {
                              const sortBy = sortByArray[0];
                              const orderDir =
                                  sortBy.direction === 'desc'
                                      ? OrderDir.DESC
                                      : OrderDir.ASC;
                              onSortChange(sortBy.key, orderDir);
                          }
                      }
                    : undefined
            }
            rowKey="key"
            rowClassName={({ data: entity }) =>
                hasErrors(entity) ? 'error-row' : 'unclickable'
            }
            paginated
            page={page}
            pageSize={pageSize}
            onPageChange={onPageChange}
            onPageSizeChange={onPageSizeChange}
            totalCount={totalEntityCount}
            expandedRows={expandedRows}
            columnDefs={columnDefsWithStatus}
        />
    );
};

interface MetadataErrorReportProps {
    bulkSessionId: string;
    setHasColumnErrors: (value: boolean) => void;
    setHasOutdatedTemplate: (value: boolean) => void;
}

const TAB_PROJECTS = 'projects';
const TAB_PRODUCTS = 'products';

export const getProjectColumnDefs = (): ColumnDefinition<Project>[] => [
    {
        sortable: true,
        name: 'name',
        title: $t(
            'bulkDigitalAudio.metadataErrorReport.tableHeaders.projectName'
        ),
        Cell: ({ data }: { data: Project }) => (
            <div className="truncated-cell" title={data.name ?? undefined}>
                {data.name}
            </div>
        ),
    },
    {
        name: 'projectCode',
        title: $t(
            'bulkDigitalAudio.metadataErrorReport.tableHeaders.projectCode'
        ),
        Cell: ({ data }: { data: Project }) => (
            <div
                className="truncated-cell"
                title={data.projectCode ?? undefined}
            >
                {data.projectCode}
            </div>
        ),
    },
];

export const getProductColumnDefs = (): ColumnDefinition<Product>[] => [
    {
        sortable: true,
        name: 'name',
        title: $t(
            'bulkDigitalAudio.metadataErrorReport.tableHeaders.productName'
        ),
        Cell: ({ data }: { data: Product }) => (
            <div className="truncated-cell" title={data.name ?? undefined}>
                {data.name}
            </div>
        ),
    },
    {
        name: 'productCode',
        title: $t(
            'bulkDigitalAudio.metadataErrorReport.tableHeaders.productCode'
        ),
        Cell: ({ data }: { data: Product }) => (
            <div
                className="truncated-cell"
                title={data.productCode ?? undefined}
            >
                {data.productCode}
            </div>
        ),
    },
];

// Product-specific helpers
export const hasProductErrors = (product: Product): boolean =>
    product.errors.length > 0 ||
    !!product.tracks?.some(track => track.errors.length > 0);

// Project-specific helpers
export const hasProjectErrors = (project: Project): boolean =>
    project.errors.length > 0;

const MetadataErrorReport = ({
    bulkSessionId,
    setHasColumnErrors,
    setHasOutdatedTemplate,
}: MetadataErrorReportProps) => {
    const getMetadataReportQuery = useGetMetadataReportQuery();
    const [failedProductsCount, setFailedProductsCount] = useState(0);
    const [failedProjectsCount, setFailedProjectsCount] = useState(0);
    const [tabKey, setTabKey] = useState<string>(TAB_PROJECTS);
    const [products, setProducts] = useState<Product[] | null>(null);
    const [projects, setProjects] = useState<Project[] | null>(null);
    const [totalProductCount, setTotalProductCount] = useState(0);
    const [totalProjectCount, setTotalProjectCount] = useState(0);
    const [loading, setLoading] = useState(true);
    const [pageSize, setPageSize] = useState(10);
    const [isFirstLoad, setIsFirstLoad] = useState(true);
    const [showLocalizationWarning, setShowLocalizationWarning] =
        useState(false);

    const [productSortBy, setProductSortBy] = useState<BulkSessionSortBy>(
        BulkSessionSortBy.NAME
    );
    const [productSortOrder, setProductSortOrder] = useState<OrderDir>(
        OrderDir.ASC
    );
    const [projectSortBy, setProjectSortBy] = useState<BulkSessionSortBy>(
        BulkSessionSortBy.NAME
    );
    const [projectSortOrder, setProjectSortOrder] = useState<OrderDir>(
        OrderDir.ASC
    );

    useEffect(() => {
        if (isFirstLoad)
            getMetadataReportQuery(
                bulkSessionId,
                pageSize,
                0,
                0,
                productSortBy,
                productSortOrder,
                projectSortBy,
                projectSortOrder
            )
                .then(result => {
                    if (result) {
                        const hasNoMatchingWorksheets =
                            result.workbookErrors?.some(
                                e => e?.key === 'No Matching Worksheets'
                            );
                        if (hasNoMatchingWorksheets) {
                            setHasColumnErrors(true);
                        } else if (result.columnErrors?.length) {
                            setHasColumnErrors(true);
                            const hasMissingColumns = result.columnErrors.some(
                                ce =>
                                    ce?.errors?.some(
                                        e =>
                                            e?.key === 'Missing Column' ||
                                            e?.key === 'Extra Column'
                                    )
                            );
                            if (hasMissingColumns) setHasOutdatedTemplate(true);
                        } else {
                            setProducts(result.products);
                            setProjects(result.projects);
                            setFailedProductsCount(
                                result.productErrorCount ?? 0
                            );
                            setFailedProjectsCount(
                                result.projectErrorCount ?? 0
                            );
                            setTotalProjectCount(result.totalProjects ?? 0);
                            setTotalProductCount(result.totalProducts ?? 0);
                            setShowLocalizationWarning(
                                result.containsIllegalLocalizations ?? false
                            );
                        }
                    }
                    setLoading(false);
                    setIsFirstLoad(false);
                })
                .catch(() => {
                    setLoading(false);
                });
    }, [
        getMetadataReportQuery,
        bulkSessionId,
        pageSize,
        isFirstLoad,
        productSortBy,
        productSortOrder,
        projectSortBy,
        projectSortOrder,
        setHasColumnErrors,
        setHasOutdatedTemplate,
    ]);

    useEffect(() => {
        if (failedProductsCount > 0 && failedProjectsCount === 0) {
            setTabKey(TAB_PRODUCTS);
        } else {
            setTabKey(TAB_PROJECTS);
        }
    }, [failedProductsCount, failedProjectsCount]);

    const [tabPage, setTabPage] = useState<Record<string, number>>({
        [TAB_PROJECTS]: 0,
        [TAB_PRODUCTS]: 0,
    });

    const handleTabSelect = (key: string | null) => {
        if (!key) return;
        setTabKey(key);
    };

    const handlePageSelect = (tab: string, page: number) => {
        let productOffset = tabPage[TAB_PRODUCTS] * pageSize;
        let projectOffset = tabPage[TAB_PROJECTS] * pageSize;

        if (tab == TAB_PRODUCTS) productOffset = page * pageSize;
        else projectOffset = page * pageSize;

        setLoading(true);
        getMetadataReportQuery(
            bulkSessionId,
            pageSize,
            productOffset,
            projectOffset,
            productSortBy,
            productSortOrder,
            projectSortBy,
            projectSortOrder
        )
            .then(result => {
                setLoading(false);
                if (result) {
                    setProducts(result.products);
                    setProjects(result.projects);
                    setTabPage({
                        ...tabPage,
                        [tab]: page,
                    });
                }
            })
            .catch(() => {
                setLoading(false);
            });
    };

    const handleChangePageSize = (newSize: number) => {
        setLoading(true);
        getMetadataReportQuery(
            bulkSessionId,
            newSize,
            0,
            0,
            productSortBy,
            productSortOrder,
            projectSortBy,
            projectSortOrder
        )
            .then(result => {
                setLoading(false);
                if (result) {
                    setProducts(result.products);
                    setProjects(result.projects);
                    setPageSize(newSize);
                }
            })
            .catch(() => {
                setLoading(false);
            });
    };

    const handleSortChange = (
        tab: string,
        sortBy: string,
        sortOrder: OrderDir
    ) => {
        const productOffset = 0;
        const projectOffset = 0;

        let newProductSortBy = productSortBy;
        let newProductSortOrder = productSortOrder;
        let newProjectSortBy = projectSortBy;
        let newProjectSortOrder = projectSortOrder;

        if (tab === TAB_PRODUCTS) {
            newProductSortBy = mapToSortBy(sortBy);
            newProductSortOrder = sortOrder;
            setProductSortBy(newProductSortBy);
            setProductSortOrder(newProductSortOrder);
        } else {
            newProjectSortBy = mapToSortBy(sortBy);
            newProjectSortOrder = sortOrder;
            setProjectSortBy(newProjectSortBy);
            setProjectSortOrder(newProjectSortOrder);
        }

        setTabPage({
            [TAB_PROJECTS]: 0,
            [TAB_PRODUCTS]: 0,
        });

        setLoading(true);
        getMetadataReportQuery(
            bulkSessionId,
            pageSize,
            productOffset,
            projectOffset,
            newProductSortBy,
            newProductSortOrder,
            newProjectSortBy,
            newProjectSortOrder
        )
            .then(result => {
                setLoading(false);
                if (result) {
                    setProducts(result.products);
                    setProjects(result.projects);
                }
            })
            .catch(() => {
                setLoading(false);
            });
    };

    return (
        <>
            {!loading &&
                failedProjectsCount === 0 &&
                failedProductsCount === 0 && (
                    <div className="unassigned-errors-alert">
                        <Alert
                            variant="warn"
                            text={$t(
                                'bulkDigitalAudio.metadataErrorReport.unassignedErrorsWarningText'
                            )}
                        />
                    </div>
                )}
            {showLocalizationWarning && (
                <div className="illegal-localizations-alert">
                    <Alert
                        variant="warn"
                        text={$t(
                            'bulkDigitalAudio.metadataErrorReport.illegalLocalizationsWarningText'
                        )}
                    />
                </div>
            )}
            <div className="error-summary-report">
                <div className="error-summary-report-header">
                    <h3>
                        {$t(`bulkDigitalAudio.metadataErrorReport.headerTitle`)}
                    </h3>
                    <Tabs activeKey={tabKey} onSelect={handleTabSelect}>
                        <Tab
                            eventKey={TAB_PROJECTS}
                            title={` ${$t(
                                `bulkDigitalAudio.metadataErrorReport.headerTabProjects`
                            )}
        ${
            failedProjectsCount > 0
                ? ` (${failedProjectsCount} ${$t(
                      failedProjectsCount > 1
                          ? 'bulkDigitalAudio.metadataErrorReport.headerTabFails'
                          : 'bulkDigitalAudio.metadataErrorReport.headerTabFail'
                  )})`
                : ''
        }
    `}
                        ></Tab>
                        <Tab
                            eventKey={TAB_PRODUCTS}
                            title={` ${$t(
                                `bulkDigitalAudio.metadataErrorReport.headerTabProducts`
                            )}
        ${
            failedProductsCount > 0
                ? ` (${failedProductsCount} ${$t(
                      failedProductsCount > 1
                          ? 'bulkDigitalAudio.metadataErrorReport.headerTabFails'
                          : 'bulkDigitalAudio.metadataErrorReport.headerTabFail'
                  )})`
                : ''
        }
    `}
                        ></Tab>
                    </Tabs>
                </div>

                {tabKey === TAB_PROJECTS ? (
                    <MetadataErrorReportTable<Project>
                        loading={loading}
                        entities={projects}
                        columnDefs={getProjectColumnDefs()}
                        hasErrors={hasProjectErrors}
                        page={tabPage[TAB_PROJECTS]}
                        pageSize={pageSize}
                        totalEntityCount={totalProjectCount}
                        onPageChange={(page: number) =>
                            handlePageSelect(TAB_PROJECTS, page)
                        }
                        onPageSizeChange={handleChangePageSize}
                        onSortChange={(sortBy: string, sortOrder: OrderDir) =>
                            handleSortChange(TAB_PROJECTS, sortBy, sortOrder)
                        }
                        renderErrorReport={project => (
                            <JSONableProjectErrorReport project={project} />
                        )}
                    />
                ) : (
                    <MetadataErrorReportTable<Product>
                        loading={loading}
                        entities={products}
                        columnDefs={getProductColumnDefs()}
                        hasErrors={hasProductErrors}
                        page={tabPage[TAB_PRODUCTS]}
                        pageSize={pageSize}
                        totalEntityCount={totalProductCount}
                        onPageChange={(page: number) =>
                            handlePageSelect(TAB_PRODUCTS, page)
                        }
                        onPageSizeChange={handleChangePageSize}
                        onSortChange={(sortBy: string, sortOrder: OrderDir) =>
                            handleSortChange(TAB_PRODUCTS, sortBy, sortOrder)
                        }
                        renderErrorReport={product => (
                            <JSONableProductErrorReport product={product} />
                        )}
                    />
                )}
            </div>
        </>
    );
};

export default MetadataErrorReport;
