'use client';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { usePathname } from 'next/navigation';
import { Loader2, AlertCircle, LayoutDashboard, Activity, ScrollText, Map, FileCheck, Cpu, Package, GitMerge, MessageSquare, Database, Play, Square, RotateCcw, Zap, Layers, } from 'lucide-react';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../../ui/tabs.js';
import { BedrockMemorySection } from '../../bedrock-memory-section.js';
import { BedrockTargetKind } from '../../../../../../packages/core/src/domain/generated/output.js';
import { useFeatureFlags } from '../../../hooks/feature-flags-context.js';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip.js';
import { getFeaturePhaseTimings } from '../../../app/actions/get-feature-phase-timings.js';
import { getFeaturePlan } from '../../../app/actions/get-feature-plan.js';
import { cn } from '../../../lib/utils.js';
import { featureNodeStateConfig } from '../../common/feature-node/index.js';
import { CometSpinner } from '../../ui/comet-spinner.js';
import { PrdQuestionnaire } from '../../common/prd-questionnaire/index.js';
import { TechDecisionsContent } from '../../common/tech-decisions-review/index.js';
import { ProductDecisionsSummary } from '../../common/product-decisions-summary/index.js';
import { MergeReview } from '../../common/merge-review/index.js';
import { DrawerActionBar } from '../../common/drawer-action-bar/index.js';
import { OverviewTab } from './overview-tab.js';
import { ActivityTab } from './activity-tab.js';
import { LogTab } from './log-tab.js';
import { PlanTab } from './plan-tab.js';
import { ChatTab } from '../../features/chat/ChatTab.js';
import { useFeatureLogs } from '../../../hooks/use-feature-logs.js';
import { useTabDataFetch } from './use-tab-data-fetch.js';
/** All possible tabs in display order. */
const ALL_TABS = [
    { key: 'overview', label: 'Overview', icon: LayoutDashboard },
    { key: 'activity', label: 'Activity', icon: Activity },
    { key: 'log', label: 'Log', icon: ScrollText },
    { key: 'plan', label: 'Plan', icon: Map },
    { key: 'prd-review', label: 'PRD Review', icon: FileCheck },
    { key: 'tech-decisions', label: 'Tech Decisions', icon: Cpu },
    { key: 'product-decisions', label: 'Product', icon: Package },
    { key: 'merge-review', label: 'Merge Review', icon: GitMerge },
    { key: 'chat', label: 'Chat', icon: MessageSquare },
    { key: 'bedrock', label: 'Bedrock', icon: Database },
];
/** Compute which tabs are visible based on feature lifecycle + state. */
function computeVisibleTabs(node, interactiveAgentEnabled = true, bedrockIntegrationEnabled = false) {
    const tabs = ['overview', 'activity'];
    if (node.hasAgentRun) {
        tabs.push('log');
    }
    if (node.hasPlan) {
        tabs.push('plan');
    }
    if (node.lifecycle === 'requirements' && node.state === 'action-required') {
        tabs.push('prd-review');
    }
    // Tech / Product spec tabs stay visible from implementation onwards so
    // users can review the locked-in decisions while the agent works, while
    // a PR is open in review, and after the feature is merged in maintain.
    // Fast-mode features skip the spec phases entirely, so these tabs would
    // always be empty — hide them.
    if (!node.fastMode &&
        (node.lifecycle === 'implementation' ||
            node.lifecycle === 'review' ||
            node.lifecycle === 'maintain')) {
        tabs.push('tech-decisions', 'product-decisions');
    }
    if (node.lifecycle === 'review' && (node.state === 'action-required' || node.state === 'error')) {
        tabs.push('merge-review');
    }
    if (node.lifecycle === 'maintain' && node.pr) {
        tabs.push('merge-review');
    }
    // Chat tab is visible for ALL lifecycle phases when interactive agent is enabled
    if (interactiveAgentEnabled) {
        tabs.push('chat');
    }
    // Bedrock memory tab is gated behind the bedrockIntegration feature flag.
    if (bedrockIntegrationEnabled) {
        tabs.push('bedrock');
    }
    return tabs;
}
async function fetchActivity(featureId) {
    const result = await getFeaturePhaseTimings(featureId);
    if ('error' in result)
        throw new Error(result.error);
    return { timings: result.timings, rejectionFeedback: result.rejectionFeedback };
}
async function fetchPlan(featureId) {
    const result = await getFeaturePlan(featureId);
    if ('error' in result)
        throw new Error(result.error);
    return result.plan;
}
const TAB_FETCHERS = {
    activity: fetchActivity,
    plan: fetchPlan,
};
export function FeatureDrawerTabs({ featureName, headerContent, featureNode, featureId, initialTab, urlTab, prdData, prdSelections, onPrdSelect, onPrdApprove, onPrdReject, isPrdLoading, techData, onTechApprove, onTechReject, isTechLoading, productData, mergeData, onMergeApprove, onMergeReject, isMergeLoading, syncStatus, syncLoading, syncError, onRefreshSync, onRebaseOnMain, rebaseLoading, rebaseError, isRejecting, chatInput, onChatInputChange, pinnedConfig, continuationActionsDisabled = false, sseEvents, interactiveAgentEnabled = true, onRetry, onStop, onStart, }) {
    const pathname = usePathname();
    const { bedrockIntegration } = useFeatureFlags();
    const visibleTabs = useMemo(() => computeVisibleTabs(featureNode, interactiveAgentEnabled, bedrockIntegration), [featureNode, interactiveAgentEnabled, bedrockIntegration]);
    const visibleTabDefs = useMemo(() => ALL_TABS.filter((t) => visibleTabs.includes(t.key)).map((t) => t.key === 'merge-review' && featureNode.lifecycle === 'maintain'
        ? { ...t, label: 'Merge History' }
        : t), [visibleTabs, featureNode.lifecycle]);
    // Derive the base path (without tab segment) from the current pathname.
    // e.g. /feature/abc123/activity → /feature/abc123
    const basePath = useMemo(() => {
        const match = pathname.match(/^(\/feature\/[^/]+)/);
        return match ? match[1] : pathname;
    }, [pathname]);
    // Resolve the effective initial tab: URL path tab > initialTab prop > 'overview'
    const effectiveInitial = useMemo(() => {
        if (urlTab && visibleTabs.includes(urlTab))
            return urlTab;
        if (initialTab && visibleTabs.includes(initialTab))
            return initialTab;
        return 'overview';
        // Only compute on mount — subsequent changes are handled by effects below
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);
    const [activeTab, setActiveTab] = useState(effectiveInitial);
    // Only subscribe to log SSE when the log tab is active to avoid
    // opening an EventSource connection on every drawer open.
    const featureLogs = useFeatureLogs(activeTab === 'log' ? featureId : null);
    const { tabs, fetchTab, refreshTab } = useTabDataFetch(featureId, TAB_FETCHERS);
    // Sync URL when active tab changes via user interaction.
    // Use window.history.pushState instead of router.push to avoid triggering a
    // server component re-render (which would remount the drawer).
    const isUserInteraction = useRef(false);
    useEffect(() => {
        if (!isUserInteraction.current)
            return;
        isUserInteraction.current = false;
        // Build the target URL from the base path + tab segment
        const targetUrl = activeTab === 'overview' ? basePath : `${basePath}/${activeTab}`;
        // Only update URL if it actually changed
        if (targetUrl !== pathname) {
            window.history.pushState(null, '', targetUrl);
        }
    }, [activeTab, basePath, pathname]);
    // Sync active tab from URL when pathname changes (e.g. browser back/forward).
    // Skip on initial mount — the effectiveInitial handles that via urlTab prop.
    const prevPathnameRef = useRef(pathname);
    useEffect(() => {
        if (prevPathnameRef.current === pathname)
            return; // Skip initial mount
        prevPathnameRef.current = pathname;
        if (isUserInteraction.current)
            return; // Skip — this is our own navigation
        const segments = pathname.split('/');
        // pathname is /feature/[id] or /feature/[id]/[tab]
        const pathTab = segments.length >= 4 ? segments[3] : undefined;
        const resolved = pathTab && visibleTabs.includes(pathTab) ? pathTab : 'overview';
        if (resolved !== activeTab) {
            setActiveTab(resolved);
            if (resolved === 'activity' || resolved === 'plan') {
                fetchTab(resolved);
            }
        }
    }, [pathname]); // eslint-disable-line react-hooks/exhaustive-deps
    // On mount, sync the URL to reflect the effective initial tab when it was
    // derived from feature state (initialTab) rather than from the URL (urlTab).
    // Use replaceState so we don't add a duplicate history entry.
    const initialSyncDone = useRef(false);
    useEffect(() => {
        if (initialSyncDone.current)
            return;
        initialSyncDone.current = true;
        // Only sync if the effective tab came from initialTab (not from URL)
        if (!urlTab && effectiveInitial !== 'overview') {
            const targetUrl = `${basePath}/${effectiveInitial}`;
            if (targetUrl !== pathname) {
                window.history.replaceState(null, '', targetUrl);
            }
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);
    // Trigger lazy fetch for URL-driven initial tab
    const initialFetchDone = useRef(false);
    useEffect(() => {
        if (initialFetchDone.current)
            return;
        initialFetchDone.current = true;
        if (activeTab === 'activity' || activeTab === 'plan') {
            fetchTab(activeTab);
        }
    }, [activeTab, fetchTab]);
    // Reset tab when featureId changes
    const prevFeatureIdRef = useRef(featureId);
    useEffect(() => {
        if (prevFeatureIdRef.current !== featureId) {
            prevFeatureIdRef.current = featureId;
            setActiveTab('overview');
        }
    }, [featureId]);
    // When initialTab changes (e.g. SSE updates lifecycle), switch to it if visible
    // and sync the URL with replaceState so the address bar reflects the new tab.
    // Also trigger lazy fetch for the new tab so data is ready immediately.
    const prevInitialTabRef = useRef(initialTab);
    useEffect(() => {
        if (prevInitialTabRef.current !== initialTab &&
            initialTab &&
            visibleTabs.includes(initialTab)) {
            prevInitialTabRef.current = initialTab;
            setActiveTab(initialTab);
            // Trigger lazy fetch for the new tab if it's a lazy-loaded tab
            if (initialTab === 'activity' || initialTab === 'plan') {
                fetchTab(initialTab);
            }
            // Sync URL to match the new tab
            const targetUrl = initialTab === 'overview' ? basePath : `${basePath}/${initialTab}`;
            if (targetUrl !== window.location.pathname) {
                window.history.replaceState(null, '', targetUrl);
            }
        }
    }, [initialTab, visibleTabs, basePath, fetchTab]);
    // If the active tab becomes invisible (lifecycle changed), fall back to overview
    // and sync the URL accordingly.
    useEffect(() => {
        if (!visibleTabs.includes(activeTab)) {
            setActiveTab('overview');
            if (window.location.pathname !== basePath) {
                window.history.replaceState(null, '', basePath);
            }
        }
    }, [visibleTabs, activeTab, basePath]);
    // SSE refresh: re-fetch lazy tab data when relevant SSE events arrive
    // for this feature (e.g. PhaseCompleted, AgentStarted, AgentCompleted).
    // Always refresh 'activity' data (even if not the active tab) so switching
    // to the activity tab shows up-to-date timings without a loading flash.
    const activeTabRef = useRef(activeTab);
    activeTabRef.current = activeTab;
    const sseProcessedRef = useRef(0);
    useEffect(() => {
        if (!sseEvents || sseEvents.length === 0)
            return;
        // Clamp cursor if events were pruned
        if (sseProcessedRef.current > sseEvents.length) {
            sseProcessedRef.current = 0;
        }
        if (sseEvents.length <= sseProcessedRef.current)
            return;
        const newEvents = sseEvents.slice(sseProcessedRef.current);
        sseProcessedRef.current = sseEvents.length;
        const hasRelevantEvent = newEvents.some((e) => e.featureId === featureId);
        if (!hasRelevantEvent)
            return;
        // Always refresh activity data so it stays current for when the user switches tabs
        refreshTab('activity');
        const current = activeTabRef.current;
        if (current === 'plan') {
            refreshTab(current);
        }
    }, [sseEvents, featureId, refreshTab]);
    // Poll activity data while the feature is actively running.
    // SSE events only fire on state transitions (phase completed, lifecycle changed),
    // so during a long-running phase there are no events and the data goes stale.
    // Poll every 5s when the feature is in a working state to keep data fresh.
    const isFeatureActive = featureNode.state === 'running' || featureNode.state === 'creating';
    useEffect(() => {
        if (!isFeatureActive)
            return;
        const interval = setInterval(() => {
            refreshTab('activity');
        }, 5000);
        return () => clearInterval(interval);
    }, [isFeatureActive, refreshTab]);
    const handleTabChange = useCallback((value) => {
        const tab = value;
        isUserInteraction.current = true;
        setActiveTab(tab);
        if (tab === 'activity' || tab === 'plan') {
            fetchTab(tab);
        }
    }, [fetchTab]);
    return (_jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: _jsxs(Tabs, { value: activeTab, onValueChange: handleTabChange, className: "flex min-h-0 flex-1 flex-col", children: [_jsx(TabsList, { className: "bg-muted/50 h-auto w-full shrink-0 justify-start gap-0 rounded-none border-b p-0", children: visibleTabDefs.map((tab) => {
                        const Icon = tab.icon;
                        return (_jsxs(TabsTrigger, { value: tab.key, className: "text-muted-foreground hover:bg-muted hover:text-foreground data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:border-t-primary [&:not([data-state=active])]:border-r-border relative h-auto rounded-none border-t-2 border-r border-t-transparent border-r-transparent bg-transparent px-3.5 py-2.5 text-[13px] font-normal shadow-none transition-none last:border-r-transparent data-[state=active]:shadow-none", children: [_jsx(Icon, { className: "mr-1.5 size-4" }), tab.label] }, tab.key));
                    }) }), _jsxs("div", { className: "bg-muted/40 shrink-0 border-b", children: [featureName ? (_jsxs("div", { className: "flex h-12 items-stretch gap-2 pr-0 pl-4", "data-testid": "feature-drawer-header", children: [_jsx("div", { className: "flex items-center", children: featureNode.fastMode ? (_jsx(Zap, { className: "size-4 shrink-0 text-amber-500" })) : (_jsx(Layers, { className: "text-muted-foreground/50 size-4 shrink-0" })) }), _jsx("h2", { className: "text-foreground flex min-w-0 items-center truncate text-base font-semibold tracking-tight", children: featureName }), featureNode.repositoryName ? (_jsxs("span", { className: "animate-in fade-in flex shrink-0 items-center gap-1.5 self-center duration-200", children: [_jsx("span", { className: "text-muted-foreground/30 text-sm", children: "/" }), featureNode.remoteUrl ? (_jsx("a", { href: featureNode.remoteUrl, target: "_blank", rel: "noopener noreferrer", className: "text-muted-foreground hover:text-foreground text-sm", children: featureNode.repositoryName })) : (_jsx("span", { className: "text-muted-foreground text-sm", children: featureNode.repositoryName }))] })) : (_jsxs("span", { className: "flex items-center gap-1.5 self-center", children: [_jsx("span", { className: "text-muted-foreground/30 text-sm", children: "/" }), _jsx("span", { className: "bg-muted h-4 w-16 animate-pulse rounded" })] })), _jsx(TooltipProvider, { delayDuration: 300, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "ml-auto flex shrink-0 cursor-default items-center self-stretch text-xs font-medium", children: [_jsxs("div", { className: cn('flex items-center gap-1.5 self-stretch px-3', featureNodeStateConfig[featureNode.state].labelClass), children: [featureNode.state === 'running' ? (_jsx(CometSpinner, { size: "sm", className: "shrink-0" })) : ((() => {
                                                                    const I = featureNodeStateConfig[featureNode.state].icon;
                                                                    return _jsx(I, { className: "size-3.5 shrink-0" });
                                                                })()), featureNodeStateConfig[featureNode.state].label] }), featureNode.state === 'pending' && onStart ? (_jsxs("button", { type: "button", onClick: () => onStart(featureNode.featureId), disabled: continuationActionsDisabled, className: "text-muted-foreground flex items-center gap-1 self-stretch px-3 hover:bg-green-500/10 hover:text-green-600 disabled:pointer-events-none disabled:opacity-50 dark:hover:text-green-400", "data-testid": "feature-drawer-start-button", children: [_jsx(Play, { className: "size-3.5" }), " Start"] })) : featureNode.state === 'error' && onRetry ? (_jsxs("button", { type: "button", onClick: () => onRetry(featureNode.featureId), disabled: continuationActionsDisabled, className: "text-muted-foreground flex items-center gap-1 self-stretch px-3 hover:bg-red-500/10 hover:text-red-500 disabled:pointer-events-none disabled:opacity-50 dark:hover:text-red-400", "data-testid": "feature-drawer-retry-button", children: [_jsx(RotateCcw, { className: "size-3.5" }), " Retry"] })) : featureNode.state === 'running' && onStop ? (_jsxs("button", { type: "button", onClick: () => onStop(featureNode.featureId), className: "text-muted-foreground flex items-center gap-1 self-stretch px-3 hover:bg-red-500/10 hover:text-red-500 dark:hover:text-red-400", "data-testid": "feature-drawer-stop-button", children: [_jsx(Square, { className: "size-3.5" }), " Stop"] })) : null] }) }), featureNode.errorMessage ? (_jsxs(TooltipContent, { side: "bottom", align: "end", sideOffset: 4, className: "z-[100] max-w-xs cursor-pointer text-xs leading-relaxed select-text", onClick: () => {
                                                    void navigator.clipboard.writeText(featureNode.errorMessage);
                                                }, children: [featureNode.errorMessage, _jsx("span", { className: "text-muted-foreground ml-1 text-[10px] italic", children: "(click to copy)" })] })) : null] }) })] })) : null, headerContent] }), _jsx(TabsContent, { value: "overview", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(OverviewTab, { data: featureNode, pinnedConfig: pinnedConfig, syncStatus: syncStatus, syncLoading: syncLoading, syncError: syncError, onRefreshSync: onRefreshSync, onRebaseOnMain: onRebaseOnMain, rebaseLoading: rebaseLoading, rebaseError: rebaseError }) }), _jsx(TabsContent, { value: "activity", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(ActivityTab, { timings: tabs.activity.data?.timings ?? null, loading: tabs.activity.loading, error: tabs.activity.error, rejectionFeedback: tabs.activity.data?.rejectionFeedback }) }), _jsx(TabsContent, { value: "log", className: "mt-0 flex-1 overflow-hidden", children: _jsx(LogTab, { content: featureLogs.content, isConnected: featureLogs.isConnected, error: featureLogs.error }) }), _jsx(TabsContent, { value: "plan", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(PlanTab, { plan: tabs.plan.data, loading: tabs.plan.loading, error: tabs.plan.error }) }), visibleTabs.includes('prd-review') ? (_jsx(TabsContent, { value: "prd-review", className: "mt-0 flex min-h-0 flex-1 flex-col", children: prdData ? (_jsx(PrdQuestionnaire, { data: prdData, selections: prdSelections ?? {}, onSelect: onPrdSelect ?? (() => undefined), onApprove: onPrdApprove ?? (() => undefined), onReject: onPrdReject, isProcessing: Boolean((isPrdLoading ?? false) || continuationActionsDisabled), isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) })) : null, visibleTabs.includes('tech-decisions') ? (_jsx(TabsContent, { value: "tech-decisions", className: "mt-0 flex min-h-0 flex-1 flex-col", children: techData ? (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [_jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx(TechDecisionsContent, { data: techData }) }), featureNode.lifecycle === 'implementation' &&
                                featureNode.state === 'action-required' ? (_jsx(DrawerActionBarForTech, { onApprove: onTechApprove ?? (() => undefined), onReject: onTechReject, isProcessing: Boolean((isTechLoading ?? false) || continuationActionsDisabled), isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })) : null] })) : isTechLoading ? (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) : (_jsx("p", { className: "text-muted-foreground p-4 text-center text-sm", children: "No technical decisions available." })) })) : null, visibleTabs.includes('product-decisions') ? (_jsx(TabsContent, { value: "product-decisions", className: "mt-0 flex-1 overflow-y-auto", children: productData === null ? (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) : productData ? (_jsx(ProductDecisionsSummary, { data: productData })) : (_jsx("p", { className: "text-muted-foreground p-4 text-center text-sm", children: "No product decisions available." })) })) : null, visibleTabs.includes('merge-review') ? (_jsx(TabsContent, { value: "merge-review", className: "mt-0 flex min-h-0 flex-1 flex-col", children: mergeData ? (_jsx(MergeReview, { data: mergeData, readOnly: featureNode.lifecycle === 'maintain', onApprove: onMergeApprove ?? (() => undefined), onReject: onMergeReject, isProcessing: Boolean((isMergeLoading ?? false) || continuationActionsDisabled), isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: isMergeLoading ? (_jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" })) : (_jsxs("div", { className: "text-muted-foreground flex flex-col items-center gap-2 text-sm", children: [_jsx(AlertCircle, { className: "h-6 w-6" }), _jsx("span", { children: "Merge review data unavailable" })] })) })) })) : null, visibleTabs.includes('chat') ? (_jsx(TabsContent, { value: "chat", className: "mt-0 flex min-h-0 flex-1 flex-col overflow-hidden", children: _jsx(ChatTab, { featureId: featureId, worktreePath: featureNode.worktreePath }) })) : null, visibleTabs.includes('bedrock') ? (_jsx(TabsContent, { value: "bedrock", className: "mt-0 flex-1 overflow-y-auto p-4", children: _jsx(BedrockMemorySection, { targetKind: BedrockTargetKind.Feature, targetId: featureId, targetLabel: featureNode.name ?? featureId, initialEnabled: false }) })) : null] }) }));
}
// ── Private helper ──────────────────────────────────────────────────────
function DrawerActionBarForTech({ onApprove, onReject, isProcessing, isRejecting, chatInput, onChatInputChange, }) {
    const { t } = useTranslation('web');
    return (_jsx(DrawerActionBar, { onReject: onReject, onApprove: onApprove, approveLabel: t('featureDrawer.approvePlan'), revisionPlaceholder: "Ask AI to revise the plan...", isProcessing: isProcessing, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange }));
}
