//
//  TimeDisplayView.swift
//  TheNoiseClock
//
//  Created by Matt Bruce on 9/7/25.
//

import SwiftUI

/// Component for displaying segmented time with customizable formatting
struct TimeDisplayView: View {
    
    // MARK: - Properties
    let date: Date
    let use24Hour: Bool
    let showSeconds: Bool
    let digitColor: Color
    let glowIntensity: Double
    let manualScale: Double
    let stretched: Bool
    let clockOpacity: Double
    let fontFamily: String
    let fontWeight: String
    let fontDesign: String
    
    // MARK: - Formatters
    private static let hour24DF: DateFormatter = {
        let df = DateFormatter()
        df.locale = Locale(identifier: "en_US_POSIX")
        df.dateFormat = "HH"
        return df
    }()
    
    private static let hour12DF: DateFormatter = {
        let df = DateFormatter()
        df.locale = Locale(identifier: "en_US_POSIX")
        df.dateFormat = "h"
        return df
    }()
    
    private static let minuteDF: DateFormatter = {
        let df = DateFormatter()
        df.locale = Locale(identifier: "en_US_POSIX")
        df.dateFormat = "mm"
        return df
    }()
    
    private static let secondDF: DateFormatter = {
        let df = DateFormatter()
        df.locale = Locale(identifier: "en_US_POSIX")
        df.dateFormat = "ss"
        return df
    }()
    
    private static let ampmDF: DateFormatter = {
        let df = DateFormatter()
        df.locale = Locale(identifier: "en_US_POSIX")
        df.dateFormat = "a"
        return df
    }()
    
    // MARK: - Body
    var body: some View {
        GeometryReader { proxy in
            let size = proxy.size
            let portrait = size.height >= size.width
            
            // Use the full GeometryReader size for maximum space usage
            let fullScreenSize = size
            
            // Get safe area information for font sizing to avoid Dynamic Island overlap
            let safeAreaInsets = proxy.safeAreaInsets
            let _ = size.width - safeAreaInsets.leading - safeAreaInsets.trailing // availableWidth
            let _ = size.height - safeAreaInsets.top - safeAreaInsets.bottom // availableHeight
            
            // Use optimal font sizing that maximizes space usage with full screen
            let baseFontSize = stretched ? 
                FontUtils.maximumStretchedFontSize(
                    containerWidth: fullScreenSize.width,
                    containerHeight: fullScreenSize.height,
                    isPortrait: portrait,
                    showSeconds: showSeconds,
                    showAmPm: false
                ) :
                FontUtils.optimalFontSize(
                    containerWidth: fullScreenSize.width,
                    containerHeight: fullScreenSize.height,
                    isPortrait: portrait,
                    showSeconds: showSeconds,
                    showAmPm: false
                )
            let ampmFontSize = FontUtils.ampmFontSize(baseFontSize: baseFontSize)
            
            // Time components
            let hour = use24Hour ? Self.hour24DF.string(from: date) : Self.hour12DF.string(from: date)
            let minute = Self.minuteDF.string(from: date)
            let secondsText = Self.secondDF.string(from: date)
            let ampmText = Self.ampmDF.string(from: date)
            let showAMPM = false // Always use colon/dots instead of AM/PM
            
            // Calculate sizes using fixed-width approach to prevent jumping
            let digitUIFont = FontUtils.customUIFont(
                size: baseFontSize,
                family: fontFamily,
                weight: fontWeight,
                design: fontDesign
            )
            let ampmUIFont = FontUtils.customUIFont(
                size: ampmFontSize,
                family: fontFamily,
                weight: fontWeight,
                design: fontDesign
            )
            
            // Calculate consistent sizes for layout
            let _ = measureText("8", font: digitUIFont).height // Use 8 as reference height
            
            // Calculate the width of "88" for consistent sizing
            let testFont = FontUtils.customUIFont(
                size: baseFontSize,
                family: fontFamily,
                weight: fontWeight,
                design: fontDesign
            )
            let _ = calculateMaxTextWidth(font: testFont)
            
            // Calculate width and height for a single digit (using "8" as the reference)
            let singleDigitWidth = calculateMaxTextWidth(font: testFont, text: "8")
            let singleDigitHeight = calculateMaxTextHeight(font: testFont, text: "8")
            
            // All time segments use the same fixed width and height to prevent shifting
            let hourSize = CGSize(width: singleDigitWidth * 2, height: singleDigitHeight)
            let minuteSize = CGSize(width: singleDigitWidth * 2, height: singleDigitHeight)
            let secondsSize = showSeconds ? CGSize(width: singleDigitWidth * 2, height: singleDigitHeight) : .zero
            let ampmSize = showAMPM ? measureText(ampmText, font: ampmUIFont) : .zero
            
            // Separators - reasonable spacing with extra padding in landscape
            let dotDiameter = baseFontSize * 0.20
            let hSpacing = portrait ? baseFontSize * 0.18 : baseFontSize * 0.25  // More spacing in landscape
            let vSpacing = portrait ? baseFontSize * 0.22 : baseFontSize * 0.30  // More spacing in landscape
            let horizontalSepSize = CGSize(width: dotDiameter * 2 + hSpacing, height: dotDiameter)
            let verticalSepSize = CGSize(width: dotDiameter, height: dotDiameter * 2 + vSpacing)
            
            // Calculate layout
            let (totalWidth, totalHeight) = calculateLayoutSize(
                portrait: portrait,
                hourSize: hourSize,
                minuteSize: minuteSize,
                secondsSize: secondsSize,
                ampmSize: ampmSize,
                horizontalSepSize: horizontalSepSize,
                verticalSepSize: verticalSepSize,
                showSeconds: showSeconds,
                showAMPM: showAMPM
            )
            
            // Calculate scale with maximum space utilization using full screen
            let safeInset = AppConstants.Defaults.safeInset
            let availableW = max(1, fullScreenSize.width - safeInset * 2)
            let availableH = max(1, fullScreenSize.height - safeInset * 2)
            
            // Calculate scaling factors
            let widthScale = availableW / max(totalWidth, 1)
            let heightScale = availableH / max(totalHeight, 1)
            
            // For stretched mode, use reasonable scaling
            let effectiveScale = stretched ? 
                max(0.1, min(min(widthScale, heightScale), 1.5)) : // Use min scale and cap at 1.5x to prevent overflow
                max(0.1, max(0.1, min(widthScale, heightScale)) * CGFloat(max(0.1, min(manualScale, 1.0))))
            
            let finalScale = effectiveScale
            
            // Time display with consistent centering and stable layout
            Group {
                if portrait {
                    VStack(spacing: 0) {
                        TimeSegment(text: hour, fontSize: baseFontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
                        if showAMPM {
                            TimeSegment(text: ampmText, fontSize: ampmFontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
                        } else {
                            HorizontalColon(dotDiameter: dotDiameter, spacing: hSpacing, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight)
                        }
                        TimeSegment(text: minute, fontSize: baseFontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
                        if showSeconds {
                            HorizontalColon(dotDiameter: dotDiameter, spacing: hSpacing, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight)
                            TimeSegment(text: secondsText, fontSize: baseFontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
                        } else {
                            // Invisible placeholder to maintain consistent spacing
                            Spacer()
                                .frame(height: baseFontSize * 0.3)
                        }
                    }
                } else {
                    HStack(spacing: baseFontSize * 0.035) {
                        TimeSegment(text: hour, fontSize: baseFontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
                        if showAMPM {
                            TimeSegment(text: ampmText, fontSize: ampmFontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
                        } else {
                            VerticalColon(dotDiameter: dotDiameter, spacing: vSpacing, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight)
                        }
                        TimeSegment(text: minute, fontSize: baseFontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
                        if showSeconds {
                            VerticalColon(dotDiameter: dotDiameter, spacing: vSpacing, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight)
                            TimeSegment(text: secondsText, fontSize: baseFontSize, opacity: clockOpacity, digitColor: digitColor, glowIntensity: glowIntensity, fontFamily: fontFamily, fontWeight: fontWeight, fontDesign: fontDesign)
                        } else {
                            // Invisible placeholder to maintain consistent spacing
                            Spacer()
                                .frame(width: baseFontSize * 0.3)
                        }
                    }
                }
            }
                    .frame(width: fullScreenSize.width, height: fullScreenSize.height, alignment: .center)
            .scaleEffect(finalScale, anchor: .center)
            .animation(UIConstants.AnimationCurves.smooth, value: finalScale)
            .animation(UIConstants.AnimationCurves.smooth, value: showSeconds) // Smooth animation for seconds toggle
            .minimumScaleFactor(0.1)
            .clipped() // Prevent overflow beyond bounds
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .onOrientationChange() // Force updates on orientation changes
    }
    
    // MARK: - Helper Methods
    private func measureText(_ text: String, font: UIFont) -> CGSize {
        return FontUtils.measureTextSize(text: text, font: font)
    }
    
    private func calculateLayoutSize(
        portrait: Bool,
        hourSize: CGSize,
        minuteSize: CGSize,
        secondsSize: CGSize,
        ampmSize: CGSize,
        horizontalSepSize: CGSize,
        verticalSepSize: CGSize,
        showSeconds: Bool,
        showAMPM: Bool
    ) -> (CGFloat, CGFloat) {
        if portrait {
            var widths: [CGFloat] = [hourSize.width, minuteSize.width]
            var totalH: CGFloat = hourSize.height + minuteSize.height
            
            if showAMPM {
                widths.append(ampmSize.width)
                totalH += ampmSize.height
            } else {
                widths.append(horizontalSepSize.width)
                totalH += horizontalSepSize.height
            }
            
            if showSeconds {
                widths.append(contentsOf: [horizontalSepSize.width, secondsSize.width])
                totalH += horizontalSepSize.height + secondsSize.height
            }
            
            return (widths.max() ?? 0, totalH)
        } else {
            var totalW: CGFloat = hourSize.width + minuteSize.width
            var heights: [CGFloat] = [hourSize.height, minuteSize.height]
            
            if showAMPM {
                totalW += ampmSize.width
                heights.append(ampmSize.height)
            } else {
                totalW += verticalSepSize.width
                heights.append(verticalSepSize.height)
            }
            
            if showSeconds {
                totalW += verticalSepSize.width + secondsSize.width
                heights.append(contentsOf: [verticalSepSize.height, secondsSize.height])
            }
            
            return (totalW, heights.max() ?? 0)
        }
    }
}

// MARK: - Supporting Views

    // Calculate width of text for the given font - this ensures consistent width
    private func calculateMaxTextWidth(font: UIFont, text: String = "88") -> CGFloat {
        let attributes = [NSAttributedString.Key.font: font]
        let size = (text as NSString).size(withAttributes: attributes)
        return size.width
    }
    
    // Calculate height of text for the given font - this ensures consistent height
    private func calculateMaxTextHeight(font: UIFont, text: String = "8") -> CGFloat {
        let attributes = [NSAttributedString.Key.font: font]
        let size = (text as NSString).size(withAttributes: attributes)
        return size.height
    }

    private struct TimeSegment: View {
        let text: String
        let fontSize: CGFloat
        let opacity: Double
        let digitColor: Color
        let glowIntensity: Double
        let fontFamily: String
        let fontWeight: String
        let fontDesign: String
        
        var body: some View {
            let clamped = ColorUtils.clampOpacity(opacity)
            let font = FontUtils.customUIFont(
                size: fontSize,
                family: fontFamily,
                weight: fontWeight,
                design: fontDesign
            )
            let singleDigitWidth = calculateMaxTextWidth(font: font, text: "8")
            let singleDigitHeight = calculateMaxTextHeight(font: font, text: "8")
            let totalWidth = singleDigitWidth * CGFloat(text.count)
        
            HStack(spacing: 0) {
                ForEach(Array(text.enumerated()), id: \.offset) { index, character in
                    DigitView(
                        digit: String(character),
                        fontSize: fontSize,
                        opacity: clamped,
                        digitColor: digitColor,
                        glowIntensity: glowIntensity,
                        fontFamily: fontFamily,
                        fontWeight: fontWeight,
                        fontDesign: fontDesign,
                        digitWidth: singleDigitWidth,
                        digitHeight: singleDigitHeight
                    )
                }
            }
            .frame(width: totalWidth, alignment: .center)
        }
        
        // Calculate width of text for the given font - this ensures consistent width
        private func calculateMaxTextWidth(font: UIFont, text: String = "88") -> CGFloat {
            let attributes = [NSAttributedString.Key.font: font]
            let size = (text as NSString).size(withAttributes: attributes)
            return size.width
        }
    }
    
    private struct DigitView: View {
        let digit: String
        let fontSize: CGFloat
        let opacity: Double
        let digitColor: Color
        let glowIntensity: Double
        let fontFamily: String
        let fontWeight: String
        let fontDesign: String
        let digitWidth: CGFloat
        let digitHeight: CGFloat
        
        var body: some View {
            ZStack {
                Text(digit)
                    .font(FontUtils.customFont(
                        size: fontSize,
                        family: fontFamily,
                        weight: fontWeight,
                        design: fontDesign
                    ))
                    .foregroundColor(digitColor)
                    .blur(radius: ColorUtils.glowRadius(intensity: glowIntensity))
                    .opacity(ColorUtils.glowOpacity(intensity: glowIntensity) * opacity)
                    .multilineTextAlignment(.center)
                Text(digit)
                    .font(FontUtils.customFont(
                        size: fontSize,
                        family: fontFamily,
                        weight: fontWeight,
                        design: fontDesign
                    ))
                    .foregroundColor(digitColor)
                    .opacity(opacity)
                    .multilineTextAlignment(.center)
            }
            .frame(width: digitWidth, height: digitHeight, alignment: .center)
            .fixedSize(horizontal: false, vertical: false)
            .lineLimit(1)
            .allowsTightening(false)
            .multilineTextAlignment(.center)
        }
    }

private struct HorizontalColon: View {
    let dotDiameter: CGFloat
    let spacing: CGFloat
    let opacity: Double
    let digitColor: Color
    let glowIntensity: Double
    let fontWeight: String
    
    var body: some View {
        let clamped = ColorUtils.clampOpacity(opacity)
        HStack(spacing: spacing) {
            DotCircle(size: dotDiameter, opacity: clamped, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight)
            DotCircle(size: dotDiameter, opacity: clamped, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight)
        }
        .fixedSize(horizontal: true, vertical: true)
        .accessibilityHidden(true)
    }
}

private struct VerticalColon: View {
    let dotDiameter: CGFloat
    let spacing: CGFloat
    let opacity: Double
    let digitColor: Color
    let glowIntensity: Double
    let fontWeight: String
    
    var body: some View {
        let clamped = ColorUtils.clampOpacity(opacity)
        VStack(spacing: spacing) {
            DotCircle(size: dotDiameter, opacity: clamped, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight)
            DotCircle(size: dotDiameter, opacity: clamped, digitColor: digitColor, glowIntensity: glowIntensity, fontWeight: fontWeight)
        }
        .fixedSize(horizontal: true, vertical: true)
        .accessibilityHidden(true)
    }
}

private struct DotCircle: View {
    let size: CGFloat
    let opacity: Double
    let digitColor: Color
    let glowIntensity: Double
    let fontWeight: String
    
    var body: some View {
        let weightMultiplier = FontUtils.weightMultiplier(for: fontWeight)
        let adjustedSize = size * weightMultiplier
        
        ZStack {
            Circle()
                .fill(digitColor)
                .frame(width: adjustedSize, height: adjustedSize)
                .blur(radius: ColorUtils.glowRadius(intensity: glowIntensity))
                .opacity(ColorUtils.glowOpacity(intensity: glowIntensity) * opacity)
            Circle()
                .fill(digitColor)
                .frame(width: adjustedSize, height: adjustedSize)
                .opacity(opacity)
        }
    }
}
