import { useMemo, useCallback } from 'react';
import React from 'react';
import { Task } from '../../entities/Task';
import { TFunction } from 'i18next';
import {
    isTaskInProgress,
    isTaskPlanned,
    isTaskWaiting,
} from '../../constants/taskStatus';
import { parseDateString, getTodayDateString, toLocalDateString } from '../../utils/dateUtils';

// Check if task is in today's plan (has active status)
const isTaskInTodayPlan = (task: Task): boolean =>
    isTaskInProgress(task.status) ||
    isTaskPlanned(task.status) ||
    isTaskWaiting(task.status);

export const useProjectMetrics = (
    tasks: Task[],
    handleTaskUpdate: (task: Task) => Promise<void>,
    t: TFunction,
    showSuccessToast?: (message: string | React.ReactNode) => void
) => {
    const taskStats = useMemo(() => {
        const stats = {
            total: tasks.length,
            completed: 0,
            inProgress: 0,
            notStarted: 0,
            overdue: 0,
            dueSoon: 0,
        };

        const todayStr = getTodayDateString();
        const soonBoundary = new Date();
        soonBoundary.setHours(0, 0, 0, 0);
        soonBoundary.setDate(soonBoundary.getDate() + 7);
        const soonYear = soonBoundary.getFullYear();
        const soonMonth = String(soonBoundary.getMonth() + 1).padStart(2, '0');
        const soonDay = String(soonBoundary.getDate()).padStart(2, '0');
        const soonStr = `${soonYear}-${soonMonth}-${soonDay}`;

        const isCompleted = (status: Task['status']) =>
            status === 'done' ||
            status === 'archived' ||
            status === 2 ||
            status === 3;

        const isInProgress = (status: Task['status']) =>
            status === 'in_progress' || status === 1;

        const isNotStarted = (status: Task['status']) =>
            status === 'not_started' || status === 0;

        tasks.forEach((task) => {
            const status = task.status;

            if (isCompleted(status)) {
                stats.completed += 1;
            } else if (isInProgress(status)) {
                stats.inProgress += 1;
            } else if (isNotStarted(status)) {
                stats.notStarted += 1;
            } else {
                stats.notStarted += 1;
            }

            if (!isCompleted(status) && task.due_date) {
                const dueDateStr = task.due_date.split('T')[0];
                if (dueDateStr < todayStr) {
                    stats.overdue += 1;
                } else if (dueDateStr <= soonStr) {
                    stats.dueSoon += 1;
                }
            }
        });

        const completionRate =
            stats.total > 0
                ? Math.round((stats.completed / stats.total) * 100)
                : 0;

        return {
            ...stats,
            completionRate,
        };
    }, [tasks]);

    const completionGradient = useMemo(() => {
        if (taskStats.total === 0) {
            return 'conic-gradient(#e5e7eb 0% 100%)';
        }

        const segments = [
            { value: taskStats.completed, color: '#22c55e' },
            { value: taskStats.inProgress, color: '#3b82f6' },
            { value: taskStats.notStarted, color: '#9ca3af' },
        ];

        let current = 0;
        const gradientStops: string[] = [];

        segments.forEach((segment) => {
            if (segment.value === 0) return;
            const start = current;
            const percentage = (segment.value / taskStats.total) * 100;
            const end = start + percentage;
            gradientStops.push(
                `${segment.color} ${start}% ${Math.min(end, 100)}%`
            );
            current += percentage;
        });

        return gradientStops.length
            ? `conic-gradient(${gradientStops.join(', ')})`
            : 'conic-gradient(#e5e7eb 0% 100%)';
    }, [taskStats]);

    const dueBuckets = useMemo(() => {
        const buckets = {
            overdue: [] as Task[],
            week: [] as Task[],
            month: [] as Task[],
            unscheduled: [] as Task[],
        };

        const todayStr = getTodayDateString();
        const toDateStr = (offsetDays: number): string => {
            const d = new Date();
            d.setHours(0, 0, 0, 0);
            d.setDate(d.getDate() + offsetDays);
            const y = d.getFullYear();
            const m = String(d.getMonth() + 1).padStart(2, '0');
            const dd = String(d.getDate()).padStart(2, '0');
            return `${y}-${m}-${dd}`;
        };
        const weekStr = toDateStr(7);
        const monthStr = toDateStr(30);

        const isCompleted = (status: Task['status']) =>
            status === 'done' ||
            status === 'archived' ||
            status === 2 ||
            status === 3;

        tasks.forEach((task) => {
            if (isCompleted(task.status)) return;

            if (!task.due_date) {
                buckets.unscheduled.push(task);
                return;
            }

            const dueDateStr = task.due_date.split('T')[0];
            if (!dueDateStr) {
                buckets.unscheduled.push(task);
                return;
            }

            if (dueDateStr < todayStr) {
                buckets.overdue.push(task);
            } else if (dueDateStr <= weekStr) {
                buckets.week.push(task);
            } else if (dueDateStr <= monthStr) {
                buckets.month.push(task);
            } else {
                buckets.unscheduled.push(task);
            }
        });

        const totalDue =
            buckets.overdue.length + buckets.week.length + buckets.month.length;

        return { ...buckets, totalDue };
    }, [tasks]);

    const completionTrend = useMemo(() => {
        const days = 14;
        const today = new Date();
        const labels: { dateKey: string; label: string }[] = [];
        for (let i = days - 1; i >= 0; i--) {
            const d = new Date(today);
            d.setDate(today.getDate() - i);
            const key = toLocalDateString(d);
            labels.push({
                dateKey: key,
                label: `${d.getMonth() + 1}/${d.getDate()}`,
            });
        }

        const counts: Record<string, number> = {};
        labels.forEach((l) => (counts[l.dateKey] = 0));

        tasks.forEach((task) => {
            if (!task.completed_at) return;
            const key = toLocalDateString(new Date(task.completed_at));
            if (counts[key] !== undefined) {
                counts[key] += 1;
            }
        });

        return labels.map((l) => ({
            label: l.label,
            dateKey: l.dateKey,
            count: counts[l.dateKey] || 0,
        }));
    }, [tasks]);

    const createdTrend = useMemo(() => {
        const days = 14;
        const today = new Date();
        const labels: { dateKey: string; label: string }[] = [];
        for (let i = days - 1; i >= 0; i--) {
            const d = new Date(today);
            d.setDate(today.getDate() - i);
            const key = toLocalDateString(d);
            labels.push({
                dateKey: key,
                label: `${d.getMonth() + 1}/${d.getDate()}`,
            });
        }

        const counts: Record<string, number> = {};
        labels.forEach((l) => (counts[l.dateKey] = 0));

        tasks.forEach((task) => {
            if (!task.created_at) return;
            const key = toLocalDateString(new Date(task.created_at));
            if (counts[key] !== undefined) {
                counts[key] += 1;
            }
        });

        return labels.map((l) => ({
            label: l.label,
            dateKey: l.dateKey,
            count: counts[l.dateKey] || 0,
        }));
    }, [tasks]);

    const upcomingDueTrend = useMemo(() => {
        const days = 14;
        const today = new Date();
        const labels: { dateKey: string; label: string }[] = [];
        for (let i = 0; i < days; i++) {
            const d = new Date(today);
            d.setDate(today.getDate() + i);
            const key = toLocalDateString(d);
            labels.push({
                dateKey: key,
                label: `${d.getMonth() + 1}/${d.getDate()}`,
            });
        }

        const counts: Record<string, number> = {};
        labels.forEach((l) => (counts[l.dateKey] = 0));

        const isCompleted = (status: Task['status']) =>
            status === 'done' ||
            status === 'archived' ||
            status === 2 ||
            status === 3;

        tasks.forEach((task) => {
            if (!task.due_date || isCompleted(task.status)) return;
            // Use the due_date string directly as key (YYYY-MM-DD format)
            // This avoids timezone conversion issues with new Date().toISOString()
            const key = task.due_date.split('T')[0];
            if (counts[key] !== undefined) {
                counts[key] += 1;
            }
        });

        return labels.map((l) => ({
            label: l.label,
            dateKey: l.dateKey,
            count: counts[l.dateKey] || 0,
        }));
    }, [tasks]);

    const upcomingInsights = useMemo(() => {
        const peak = upcomingDueTrend.reduce(
            (acc, cur) => (cur.count > acc.count ? cur : acc),
            { label: '', count: 0 }
        );
        const nextThreeDays = upcomingDueTrend
            .slice(0, 3)
            .reduce((sum, d) => sum + d.count, 0);
        const nextWeek = upcomingDueTrend
            .slice(0, 7)
            .reduce((sum, d) => sum + d.count, 0);

        return {
            peakLabel: peak.label,
            peakCount: peak.count,
            nextThreeDays,
            nextWeek,
        };
    }, [upcomingDueTrend]);

    const dueHighlights = useMemo(() => {
        const combined = [
            ...dueBuckets.overdue,
            ...dueBuckets.week,
            ...dueBuckets.month,
        ];

        return combined
            .sort((a, b) => {
                const aDate = a.due_date ? new Date(a.due_date).getTime() : 0;
                const bDate = b.due_date ? new Date(b.due_date).getTime() : 0;
                return aDate - bDate;
            })
            .slice(0, 3);
    }, [dueBuckets]);

    const nextBestAction = useMemo(() => {
        const isCompleted = (status: Task['status']) =>
            status === 'done' ||
            status === 'archived' ||
            status === 2 ||
            status === 3;

        const candidates = tasks.filter(
            (task) =>
                !isCompleted(task.status) &&
                task.status !== 'in_progress' &&
                task.status !== 1
        );
        if (candidates.length === 0) return null;

        const startOfToday = new Date();
        startOfToday.setHours(0, 0, 0, 0);

        const getPriorityScore = (priority: Task['priority']) => {
            if (priority === 'high' || priority === 2) return -8;
            if (priority === 'medium' || priority === 1) return -4;
            return 0;
        };

        const scored = candidates
            .map((task) => {
                let score = 0;

                if (task.status === 'in_progress' || task.status === 1) {
                    score -= 30;
                }

                if (task.due_date) {
                    const due = parseDateString(task.due_date);
                    if (due) {
                        const diffDays = Math.floor(
                            (due.getTime() - startOfToday.getTime()) /
                                (1000 * 60 * 60 * 24)
                        );
                        if (diffDays < 0) score -= 25;
                        else if (diffDays === 0) score -= 20;
                        else if (diffDays <= 2) score -= 15;
                        else if (diffDays <= 7) score -= 10;
                    }
                }

                score += getPriorityScore(task.priority);

                if (isTaskInTodayPlan(task)) {
                    score -= 6;
                }

                const createdAt = task.created_at
                    ? new Date(task.created_at).getTime()
                    : 0;

                return {
                    task,
                    score,
                    createdAt,
                };
            })
            .sort((a, b) => {
                if (a.score !== b.score) return a.score - b.score;
                if (a.createdAt !== b.createdAt)
                    return a.createdAt - b.createdAt;
                return (a.task.id || 0) - (b.task.id || 0);
            });

        return scored[0]?.task ?? null;
    }, [tasks]);

    const getDueDescriptor = useCallback(
        (task: Task): string => {
            if (!task.due_date)
                return t('tasks.noDue', 'No due date') as string;

            const now = new Date();
            const startOfToday = new Date(
                now.getFullYear(),
                now.getMonth(),
                now.getDate()
            );
            const due = parseDateString(task.due_date);
            if (!due) return t('tasks.noDue', 'No due date') as string;

            const diffDays = Math.floor(
                (due.getTime() - startOfToday.getTime()) / (1000 * 60 * 60 * 24)
            );

            if (diffDays < 0) {
                return t('tasks.overdueBy', {
                    defaultValue: 'Overdue by {{days}}d',
                    days: Math.abs(diffDays),
                }) as string;
            }
            if (diffDays === 0)
                return t('dateIndicators.today', 'Today') as string;
            if (diffDays === 1)
                return t('dateIndicators.tomorrow', 'Tomorrow') as string;
            if (diffDays <= 7)
                return t('tasks.dueInDays', {
                    defaultValue: 'Due in {{days}}d',
                    days: diffDays,
                }) as string;

            return t('tasks.dueInDays', {
                defaultValue: 'Due in {{days}}d',
                days: diffDays,
            }) as string;
        },
        [t]
    );

    const handleStartNextAction = useCallback(async () => {
        if (!nextBestAction?.id) return;

        const isAlreadyInProgress =
            nextBestAction.status === 'in_progress' ||
            nextBestAction.status === 1;

        if (isAlreadyInProgress) {
            return;
        }

        try {
            await handleTaskUpdate({
                ...nextBestAction,
                status: 'in_progress',
            });

            if (showSuccessToast) {
                showSuccessToast(
                    t('tasks.startedSuccessfully', 'Task started successfully!')
                );
            }
        } catch {
            // Silent fail
        }
    }, [handleTaskUpdate, nextBestAction, showSuccessToast, t]);

    const weeklyPace = useMemo(() => {
        const lastWeek = completionTrend
            .slice(-7)
            .reduce((sum, d) => sum + d.count, 0);
        const prevWeek = completionTrend
            .slice(0, -7)
            .reduce((sum, d) => sum + d.count, 0);
        const delta = lastWeek - prevWeek;
        return { lastWeek, prevWeek, delta };
    }, [completionTrend]);

    const monthlyCompleted = useMemo(() => {
        const today = new Date();
        const startWindow = new Date();
        startWindow.setDate(today.getDate() - 30);
        let count = 0;
        tasks.forEach((task) => {
            if (!task.completed_at) return;
            const completedDate = new Date(task.completed_at);
            if (
                !Number.isNaN(completedDate.getTime()) &&
                completedDate >= startWindow
            ) {
                count += 1;
            }
        });
        return count;
    }, [tasks]);

    return {
        taskStats,
        completionGradient,
        dueBuckets,
        dueHighlights,
        nextBestAction,
        getDueDescriptor,
        handleStartNextAction,
        completionTrend,
        upcomingDueTrend,
        createdTrend,
        upcomingInsights,
        weeklyPace,
        monthlyCompleted,
    };
};
