//
//  DigitView.swift
//  TheNoiseClock
//
//  Created by Matt Bruce on 9/9/25.
//

import SwiftUI

/// Component for displaying a single digit with fixed width and glow effects
struct DigitView: View {
    @Environment(\.sizeCategory) private var sizeCategory
    
    let digit: String
    let fontName: FontFamily
    let weight: Font.Weight
    let design: Font.Design
    let opacity: Double
    let digitColor: Color
    let glowIntensity: Double
    let isDisplayMode: Bool
    @Binding var fontSize: CGFloat
    
    @State private var lastCalculatedSize: CGSize = .zero
    @State private var isCalculating: Bool = false
    
    init(digit: String,
         fontName: FontFamily,
         weight: Font.Weight = .regular,
         design: Font.Design = .default,
         digitColor: Color = .black,
         opacity: Double = 1,
         glowIntensity: Double = 0,
         fontSize: Binding<CGFloat>,
         isDisplayMode: Bool = false) {
        self.digit = (digit.count == 1 && "0123456789".contains(digit)) ? digit : "0"
        self.fontName = fontName
        self.weight = weight
        self.design = design
        self.opacity = opacity
        self.digitColor = digitColor
        self.glowIntensity = glowIntensity
        self.isDisplayMode = isDisplayMode
        self._fontSize = fontSize
    }
    
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                glowText
                    .position(x: geometry.size.width / 2, y: geometry.size.height / 2)
                mainText
                    .position(x: geometry.size.width / 2, y: geometry.size.height / 2)
            }
        }
    }
    
    private var glowRadius: CGFloat {
        ColorUtils.glowRadius(intensity: glowIntensity)
    }
    
    private var glowOpacity: Double {
        ColorUtils.glowOpacity(intensity: glowIntensity) * opacity
    }
    
    private var glowText: some View {
        text
            .foregroundColor(digitColor)
            .blur(radius: glowRadius)
            .opacity(glowOpacity)
    }
    
    private var mainText: some View {
        text
            .foregroundColor(digitColor)
            .opacity(opacity)
    }
    
    private var text: some View {
        GeometryReader { geometry in
            Text(digit)
                .font(FontUtils.createFont(name: fontName,
                                           weight: weight,
                                           design: design,
                                           size: fontSize))
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .multilineTextAlignment(.center)
                .minimumScaleFactor(0.1)
                .lineSpacing(0)
                .padding(.vertical, 0)
                .padding(.horizontal, 0)
                .baselineOffset(0)
                .onAppear {
                    calculateOptimalFontSize(for: geometry.size)
                }
                .onChange(of: geometry.size) { _, newSize in
                    calculateOptimalFontSize(for: newSize)
                }
                .onChange(of: sizeCategory) { _, _ in
                    calculateOptimalFontSize(for: geometry.size)
                }
                .onChange(of: fontName) { _, _ in
                    calculateOptimalFontSize(for: geometry.size)
                }
                .onChange(of: weight) { _, _ in
                    calculateOptimalFontSize(for: geometry.size)
                }
                .onChange(of: design) { _, _ in
                    calculateOptimalFontSize(for: geometry.size)
                }
        }
    }
    
    private func calculateOptimalFontSize(for size: CGSize) {
        // Prevent multiple calculations for the same size
        guard size != lastCalculatedSize && !isCalculating else { return }
        
        // Prevent multiple updates per frame
        guard !isCalculating else { return }
        isCalculating = true
        
        let optimalSize = FontUtils.calculateOptimalFontSize(digit: digit,
                                                             fontName: fontName,
                                                             weight: weight,
                                                             design: design,
                                                             for: size,
                                                             isDisplayMode: isDisplayMode)
        
        // Only update if the size is significantly different to prevent micro-adjustments
        fontSize = optimalSize
        lastCalculatedSize = size

        // Reset calculation flag after a brief delay to allow for frame completion
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.016) { // ~60fps
            isCalculating = false
        }
    }
}

// MARK: - Preview
#Preview {
    @Previewable @State var sharedFontSize: CGFloat = 2000
    @Previewable @State var fontName: FontFamily = .arial
    @Previewable @State var weight: Font.Weight = .heavy
    @Previewable @State var design: Font.Design = .rounded
    @Previewable @State var glowIntensity: Double = 0.6
    
    HStack {
        DigitView(digit: "8",
                  fontName: fontName,
                  weight: weight,
                  design: design,
                  glowIntensity: glowIntensity,
                  fontSize: $sharedFontSize)
            .border(Color.black)
        
        DigitView(digit: "1",
                  fontName: fontName,
                  weight: weight,
                  design: design,
                  glowIntensity: glowIntensity,
                  fontSize: $sharedFontSize)
            .border(Color.black)
        
        Text(":")
            .font(.system(size: sharedFontSize))
            .border(Color.black)
        
        DigitView(digit: "0",
                  fontName: fontName,
                  weight: weight,
                  design: design,
                  glowIntensity: glowIntensity,
                  fontSize: $sharedFontSize)
            .border(Color.black)
        
        DigitView(digit: "5",
                  fontName: fontName,
                  weight: weight,
                  design: design,
                  glowIntensity: glowIntensity,
                  fontSize: $sharedFontSize)
            .border(Color.black)
    }
}
