'use client';

import React, { useCallback, useMemo, useState } from 'react';
import { Alert, Input, Spin, Tree, Typography } from 'antd';
import type { DataNode, EventDataNode } from 'antd/es/tree';
import { File, Folder, FolderOpen, Search } from 'lucide-react';
import { useQueryCache } from '@/hooks/useQueryCache';
import { API_ENDPOINTS } from '@/lib/api/endpoints';
import apiClient from '@/lib/api/client';
import { mensagemErroGitlabListagem } from '@/features/projetos/utils/gitlabListagemErro';
import {
    mapRepositoryItemsToTreeNodes,
    repositoryTreeItemKey,
} from './repositorioGitTreeHelpers';
import type { RepositoryTreeItem, RepositoryTreeResponse } from './types';
import styles from './RepositorioGitTreePanel.module.scss';
import { queryKeys } from '@/lib/cache/queryKeys';

export interface RepositorioGitTreePanelProps {
    projetoId: string;
    branchRef: string;
    onOpenFile: (path: string) => void;
}

function parseTreeKey(key: string): { type: string; path: string } {
    const sep = key.indexOf(':');
    if (sep <= 0) {
        return { type: 'blob', path: key };
    }
    return { type: key.slice(0, sep), path: key.slice(sep + 1) };
}

export function RepositorioGitTreePanel({
    projetoId,
    branchRef,
    onOpenFile,
}: RepositorioGitTreePanelProps) {
    const [search, setSearch] = useState('');
    const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
    const [loadedPaths, setLoadedPaths] = useState<Record<string, DataNode[]>>({});

    const {
        data: rootData,
        isLoading: loadingRoot,
        isError: rootIsError,
        error: rootError,
        refetch: refetchRoot,
    } = useQueryCache<RepositoryTreeResponse>({
        queryKey: queryKeys.projetos.gitlabTreeLegacy(projetoId, '', branchRef),
        endpoint: API_ENDPOINTS.projetos.gitlab.repositoryTree(projetoId),
        params: { path: '', ref: branchRef },
        enabled: !!projetoId && !!branchRef,
        staleTime: 30 * 1000,
        retry: 1,
    });

    const rootNodes = useMemo(() => {
        const base = mapRepositoryItemsToTreeNodes(rootData?.items ?? []);
        return base.map((node) => {
            const parsed = parseTreeKey(String(node.key));
            if (parsed.type === 'tree' && loadedPaths[parsed.path]) {
                return { ...node, children: loadedPaths[parsed.path] };
            }
            return node;
        });
    }, [loadedPaths, rootData?.items]);

    const filteredNodes = useMemo(() => {
        const term = search.trim().toLowerCase();
        if (!term) {
            return rootNodes;
        }

        const filterRecursive = (nodes: DataNode[]): DataNode[] =>
            nodes
                .map((node) => {
                    const title = String(node.title ?? '').toLowerCase();
                    const children = node.children ? filterRecursive(node.children) : undefined;
                    const matches = title.includes(term);
                    if (matches || (children && children.length > 0)) {
                        return { ...node, children };
                    }
                    return null;
                })
                .filter(Boolean) as DataNode[];

        return filterRecursive(rootNodes);
    }, [rootNodes, search]);

    const loadTreeChildren = useCallback(
        async (path: string): Promise<DataNode[]> => {
            const { data: json } = await apiClient.get<RepositoryTreeResponse>(
                API_ENDPOINTS.projetos.gitlab.repositoryTree(projetoId),
                { params: { path, ref: branchRef } },
            );
            return mapRepositoryItemsToTreeNodes(json.items ?? []);
        },
        [branchRef, projetoId],
    );

    const onLoadData = async (node: EventDataNode<DataNode>) => {
        const parsed = parseTreeKey(String(node.key));
        if (parsed.type !== 'tree' || loadedPaths[parsed.path]) {
            return;
        }
        const children = await loadTreeChildren(parsed.path);
        setLoadedPaths((prev) => ({ ...prev, [parsed.path]: children }));
    };

    const handleSelect = (_keys: React.Key[], info: { node: EventDataNode<DataNode> }) => {
        const parsed = parseTreeKey(String(info.node.key));
        if (parsed.type === 'blob' && parsed.path) {
            onOpenFile(parsed.path);
        }
    };

    const titleRender = (node: DataNode) => {
        const parsed = parseTreeKey(String(node.key));
        const isDir = parsed.type === 'tree';
        const expanded = expandedKeys.includes(String(node.key));
        const Icon = isDir ? (expanded ? FolderOpen : Folder) : File;

        return (
            <span className={styles.treeNode}>
                <Icon size={14} aria-hidden className={styles.treeIcon} />
                <span>{node.title as React.ReactNode}</span>
            </span>
        );
    };

    if (loadingRoot) {
        return (
            <div className={styles.loadingWrap}>
                <Spin size="large" />
            </div>
        );
    }

    if (rootIsError) {
        return (
            <Alert
                type="error"
                showIcon
                message="Não foi possível carregar os arquivos do repositório"
                description={mensagemErroGitlabListagem(rootError) ?? 'Verifique permissões e conexão GitLab.'}
                action={
                    <Typography.Link onClick={() => void refetchRoot()}>Tentar novamente</Typography.Link>
                }
            />
        );
    }

    return (
        <div className={styles.panel}>
            <div className={styles.toolbar}>
                <Input
                    allowClear
                    prefix={<Search size={14} aria-hidden />}
                    placeholder="Filtrar arquivos e pastas…"
                    value={search}
                    onChange={(e) => setSearch(e.target.value)}
                    aria-label="Filtrar árvore de arquivos"
                />
            </div>
            <div className={styles.treeWrap}>
                {filteredNodes.length === 0 ? (
                    <Typography.Text type="secondary">Nenhum arquivo encontrado nesta branch.</Typography.Text>
                ) : (
                    <Tree
                        showLine
                        blockNode
                        loadData={onLoadData}
                        treeData={filteredNodes}
                        expandedKeys={expandedKeys}
                        onExpand={(keys) => setExpandedKeys(keys.map(String))}
                        onSelect={handleSelect}
                        titleRender={titleRender}
                    />
                )}
            </div>
        </div>
    );
}

/** Helper para mapear item da API em chave estável (export para testes). */
export function treeItemKeyFromApi(item: RepositoryTreeItem): string {
    return repositoryTreeItemKey(item);
}
