import { getUser } from '@/auth/authService';
import { POLLING_INTERVALS } from '@/constants';
import { fetchTaskStatus, cancelTask } from '@/services';
import { TaskStatus, type TaskResult } from '@/types';
import type { User } from 'oidc-client-ts';
import React, { useEffect, useState } from 'react';
import AlertError from './AlertError';
import { Spinner } from './Spinner';
import { HoverCard, HoverCardContent, HoverCardTrigger } from './ui/hover-card';
import { Progress } from './ui/progress';
import { Button } from './ui/button';
import { X } from 'lucide-react';

interface ActiveQueryProps {
    taskID: string | null;
    onTaskCancelled?: () => void;
}

const ActiveQuery: React.FC<ActiveQueryProps> = ({ taskID, onTaskCancelled }) => {
    const [user, setUser] = useState<User | null>(null);
    useEffect(() => {
        getUser().then(setUser);
    }, []);

    const [progressPercentage, setProgressPercentage] = useState<number>(0);
    const [taskStatus, setTaskStatus] = useState<TaskStatus | null>(TaskStatus.PENDING);
    const [lastUpdateTime, setLastUpdateTime] = useState<Date>(new Date());
    const [fetchStatusError, setFetchStatusError] = useState<string | null>(null);
    const [alertDialogIsOpen, setAlertDialogIsOpen] = useState(false);
    const [isCancelling, setIsCancelling] = useState(false);

    const handleCancelTask = async () => {
        if (!user || !taskID || isCancelling) return;

        setIsCancelling(true);
        try {
            const result = await cancelTask(user, taskID);
            if (result.success) {
                setTaskStatus(TaskStatus.REVOKED);
                onTaskCancelled?.();
            } else {
                setFetchStatusError(result.message);
                setAlertDialogIsOpen(true);
            }
        } catch (error) {
            setFetchStatusError(error instanceof Error ? error.message : 'Failed to cancel task');
            setAlertDialogIsOpen(true);
        } finally {
            setIsCancelling(false);
        }
    };

    const pollTaskStatus = async (interval: NodeJS.Timeout) => {
        if (!user || !taskID) {
            return;
        }

        try {
            const data = await fetchTaskStatus(user, taskID);
            setLastUpdateTime(new Date());
            const status = data.status as TaskStatus;
            setTaskStatus(status);

            if (status === TaskStatus.FAILURE || status === TaskStatus.REVOKED) {
                clearInterval(interval);
                setFetchStatusError('Task failed with status: ' + status);
                setAlertDialogIsOpen(true);
                return;
            }

            if (status === TaskStatus.SUCCESS) {
                clearInterval(interval);
                setProgressPercentage(100);
                return;
            }

            // Only parse result for in-progress tasks
            if (data.result) {
                try {
                    const parsedResult: TaskResult = JSON.parse(data.result);
                    setProgressPercentage(parsedResult.progress * 100);
                } catch {
                    // Result parsing failed, but task is still running - ignore
                }
            }
        } catch (error) {
            clearInterval(interval);
            setTaskStatus(TaskStatus.FAILURE);
            setAlertDialogIsOpen(true);
            if (error instanceof Error) {
                setFetchStatusError(error.message);
            } else {
                setFetchStatusError('Failed to update task status: ' + String(error));
            }
        }
    };

    useEffect(() => {
        const interval = setInterval(
            () => pollTaskStatus(interval),
            POLLING_INTERVALS.TASK_STATUS_MS
        );
        return () => clearInterval(interval);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [taskID, user]);

    if (!taskID) {
        return null;
    }

    const isInProgress = taskStatus &&
        taskStatus !== TaskStatus.SUCCESS &&
        taskStatus !== TaskStatus.FAILURE &&
        taskStatus !== TaskStatus.REVOKED;

    return (
        <>
            <div className="flex items-center gap-2 p-2 border-t bg-muted/50">
                <HoverCard>
                    <HoverCardTrigger className="flex-1">
                        <div className="flex items-center gap-2">
                            {taskStatus && <span className="text-sm">Task: {taskStatus}</span>}
                            {isInProgress && <Spinner />}
                        </div>
                        <Progress value={progressPercentage} className="mt-1" />
                    </HoverCardTrigger>
                    <HoverCardContent>
                        Task ID: {taskID}
                        <br />
                        Last updated: {lastUpdateTime.toLocaleString()}
                    </HoverCardContent>
                </HoverCard>
                {isInProgress && (
                    <Button
                        variant="ghost"
                        size="sm"
                        onClick={handleCancelTask}
                        disabled={isCancelling}
                        className="h-8 px-2 text-destructive hover:text-destructive hover:bg-destructive/10"
                    >
                        <X className="h-4 w-4" />
                        <span className="ml-1 hidden sm:inline">Cancel</span>
                    </Button>
                )}
            </div>
            <AlertError message={fetchStatusError} open={alertDialogIsOpen} setIsOpen={setAlertDialogIsOpen} />
        </>
    );
};

export default ActiveQuery;
