//
//  DemoAnimationManager.swift
//  Reflect
//
//  Manages demo animation mode for promotional videos.
//  Animates filling mood entries from top-left to bottom-right.
//

import SwiftUI
import Combine

/// Manages demo animation state for promotional video recording
@MainActor
final class DemoAnimationManager: ObservableObject {
    static let shared = DemoAnimationManager()

    /// Whether demo mode is active
    @Published var isDemoMode: Bool = false

    /// Whether the animation has started (after the 3-second delay)
    @Published var animationStarted: Bool = false

    /// Current animation progress (0.0 to 1.0)
    @Published var animationProgress: Double = 0.0

    /// The delay before starting the fill animation (in seconds)
    let startDelay: TimeInterval = 3.0

    /// Total animation duration for filling all cells in one month
    let monthAnimationDuration: TimeInterval = 1.5

    /// Delay between months (0 for fluid continuous animation)
    let monthDelay: TimeInterval = 0.0

    /// Delay between each cell in year view
    let yearCellDelay: TimeInterval = 0.05

    /// Delay between month columns in year view
    let yearMonthDelay: TimeInterval = 0.1

    /// Timer for animation progress
    private var animationTimer: Timer?
    private var startTime: Date?

    private init() {}

    /// Start demo mode - will begin animation after delay
    func startDemoMode() {
        isDemoMode = true
        animationStarted = false
        animationProgress = 0.0

        // Start animation after delay
        DispatchQueue.main.asyncAfter(deadline: .now() + startDelay) { [weak self] in
            self?.beginAnimation()
        }
    }

    /// Restart demo mode animation (for switching between tabs)
    func restartAnimation() {
        animationTimer?.invalidate()
        animationTimer = nil
        animationStarted = false
        animationProgress = 0.0
        startTime = nil

        // Start animation after delay
        DispatchQueue.main.asyncAfter(deadline: .now() + startDelay) { [weak self] in
            self?.beginAnimation()
        }
    }

    /// Stop demo mode and reset
    func stopDemoMode() {
        isDemoMode = false
        animationStarted = false
        animationProgress = 0.0
        animationTimer?.invalidate()
        animationTimer = nil
        startTime = nil
    }

    /// Begin the fill animation
    private func beginAnimation() {
        guard isDemoMode else { return }

        animationStarted = true
        startTime = Date()

        // Update progress at 60fps
        animationTimer = Timer.scheduledTimer(withTimeInterval: 1.0/60.0, repeats: true) { [weak self] _ in
            Task { @MainActor in
                self?.updateProgress()
            }
        }
    }

    /// Update animation progress - runs continuously for multi-month animation
    private func updateProgress() {
        guard let startTime = startTime else { return }

        let elapsed = Date().timeIntervalSince(startTime)
        // Progress goes from 0 to a large number (we use elapsed time directly)
        animationProgress = elapsed

        // Stop after a reasonable max time (300 seconds for year view with 0.65s per cell)
        if elapsed >= 300.0 {
            animationTimer?.invalidate()
            animationTimer = nil
        }
    }

    /// Calculate the animation time for a specific month (0-indexed from most recent)
    /// MonthView shows months in reverse chronological order, so monthIndex 0 is the current month
    func monthStartTime(monthIndex: Int) -> Double {
        return Double(monthIndex) * (monthAnimationDuration + monthDelay)
    }

    /// Returns the current month index being animated (for auto-scrolling)
    var currentAnimatingMonthIndex: Int {
        guard animationStarted else { return 0 }
        let monthDuration = monthAnimationDuration + monthDelay
        return Int(animationProgress / monthDuration)
    }

    /// Returns the approximate row being animated within current month (0-5 typically)
    func currentAnimatingRow(totalRows: Int, totalColumns: Int) -> Int {
        guard animationStarted else { return 0 }
        let monthDuration = monthAnimationDuration + monthDelay
        let progressInMonth = animationProgress.truncatingRemainder(dividingBy: monthDuration)
        let normalizedProgress = min(1.0, progressInMonth / monthAnimationDuration)
        let cellIndex = Int(normalizedProgress * Double(totalRows * totalColumns))
        return cellIndex / totalColumns
    }

    /// Check if a cell should be visible based on current animation progress
    /// For MonthView: animates cells within each month from top-left to bottom-right
    /// - Parameters:
    ///   - row: Row index within the month grid
    ///   - column: Column index within the month grid
    ///   - totalRows: Total number of rows in this month
    ///   - totalColumns: Total number of columns (7 for weekdays)
    ///   - monthIndex: Which month this is (0 = most recent/current month)
    /// - Returns: True if cell should be visible
    func isCellVisible(row: Int, column: Int, totalRows: Int, totalColumns: Int, monthIndex: Int = 0) -> Bool {
        guard animationStarted else { return false }

        // Calculate when this month's animation starts
        let monthStart = monthStartTime(monthIndex: monthIndex)

        // Check if we've reached this month yet
        if animationProgress < monthStart {
            return false
        }

        // Calculate position within this month (top-left to bottom-right)
        let totalCells = Double(totalRows * totalColumns)
        let cellIndex = Double(row * totalColumns + column)
        let normalizedPosition = cellIndex / max(1, totalCells - 1)

        // Calculate when this specific cell should appear
        let cellDelay = monthStart + (normalizedPosition * monthAnimationDuration)

        return animationProgress >= cellDelay
    }

    /// Check if a cell should be visible for YearView
    /// For YearView: animates column by column (month by month) within each year
    /// Each cell waits for the previous cell to complete before starting
    func isCellVisibleForYear(row: Int, column: Int, totalRows: Int, totalColumns: Int, yearIndex: Int = 0) -> Bool {
        guard animationStarted else { return false }

        // Calculate total cells in previous years
        let cellsPerYear = 31 * 12  // approximate max cells per year
        let yearStart = Double(yearIndex) * (Double(cellsPerYear) * yearCellDelay + yearMonthDelay)

        if animationProgress < yearStart {
            return false
        }

        // Calculate cell position: column-major order (month by month, then day within month)
        // Each month column has up to 31 days
        let cellsBeforeThisMonth = column * 31
        let cellIndex = cellsBeforeThisMonth + row

        // Add month delay between columns
        let monthDelays = Double(column) * yearMonthDelay

        // Each cell starts after the previous cell's delay
        let cellStart = yearStart + Double(cellIndex) * yearCellDelay + monthDelays

        return animationProgress >= cellStart
    }

    /// Calculate the percentage of cells visible for a month (0.0 to 1.0)
    /// Used for animating charts in demo mode
    func visiblePercentageForMonth(totalCells: Int, monthIndex: Int) -> Double {
        guard animationStarted else { return 0.0 }

        let monthStart = monthStartTime(monthIndex: monthIndex)

        // Before this month starts
        if animationProgress < monthStart {
            return 0.0
        }

        // Calculate how far through the month animation we are
        let progressInMonth = animationProgress - monthStart
        let percentage = min(1.0, progressInMonth / monthAnimationDuration)

        return percentage
    }

    /// Calculate the percentage of cells visible for a year (0.0 to 1.0)
    /// Used for animating charts in year view demo mode
    func visiblePercentageForYear(totalCells: Int, yearIndex: Int) -> Double {
        guard animationStarted else { return 0.0 }

        // Calculate when this year's animation starts
        let cellsPerYear = 31 * 12
        let yearStart = Double(yearIndex) * (Double(cellsPerYear) * yearCellDelay + yearMonthDelay)

        // Before this year starts
        if animationProgress < yearStart {
            return 0.0
        }

        // Total year duration based on cell delays and month delays
        let yearDuration = Double(cellsPerYear) * yearCellDelay + 12.0 * yearMonthDelay
        let progressInYear = animationProgress - yearStart
        let percentage = min(1.0, progressInYear / yearDuration)

        return percentage
    }

    /// Generate a random mood biased towards positive values
    /// Distribution: Great 35%, Good 30%, Average 20%, Bad 10%, Horrible 5%
    static func randomPositiveMood() -> Mood {
        let random = Double.random(in: 0...1)
        switch random {
        case 0..<0.35:
            return .great
        case 0.35..<0.65:
            return .good
        case 0.65..<0.85:
            return .average
        case 0.85..<0.95:
            return .bad
        default:
            return .horrible
        }
    }
}
