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

import Foundation
import SwiftUI
import UIKit

/// Font sizing and typography utilities
struct FontUtils {
    
    static func calculateOptimalFontSize(
        digit: String,
        fontName: FontFamily,
        weight: Font.Weight,
        design: Font.Design,
        for size: CGSize,
        isDisplayMode: Bool = false
    ) -> CGFloat {
        var low: CGFloat = 1.0
        var high: CGFloat = 2000.0
        
        while high - low > 0.01 {
            let mid = (low + high) / 2
            let testFont = createUIFont(
                name: fontName,
                weight: weight,
                design: design,
                size: mid
            )
            let textSize = tightBoundingBox(for: digit, withFont: testFont)
            
            if textSize.width <= size.width && textSize.height <= size.height {
                low = mid
            } else {
                high = mid
            }
        }
        
        // Apply more conservative sizing in full screen mode
        let baseSize = low * fontName.percentageDownsize
        return isDisplayMode ? baseSize * 0.95 : baseSize
    }
    
    static func createFont(
        name: FontFamily,
        weight: Font.Weight,
        design: Font.Design,
        size: CGFloat
    ) -> Font {
        if name == .system {
            return .system(size: size, weight: weight, design: design)
        } else {
            return .custom(weightedFontName(
                name: name,
                weight: weight,
                design: design
            ), size: size)
        }
    }
    
    private static func createUIFont(
        name: FontFamily,
        weight: Font.Weight,
        design: Font.Design,
        size: CGFloat
    ) -> UIFont {
        if name == .system {
            return UIFont.systemFont(
                ofSize: size,
                weight: weight.uiFontWeight,
                width: design.uiFontWidth
            )
        }
        
        if let font = UIFont(
            name: weightedFontName(
                name: name,
                weight: weight,
                design: design
            ),
            size: size
        ) {
            return font
        }
        
        return UIFont.systemFont(
            ofSize: size,
            weight: weight.uiFontWeight,
            width: design.uiFontWidth
        )
    }
    
    private static func tightBoundingBox(
        for text: String,
        withFont font: UIFont
    ) -> CGSize {
        let attributedString = NSAttributedString(
            string: text,
            attributes: [.font: font]
        )
        let rect = attributedString.boundingRect(
            with: CGSize(
                width: CGFloat.greatestFiniteMagnitude,
                height: CGFloat.greatestFiniteMagnitude
            ),
            options: [.usesLineFragmentOrigin, .usesFontLeading],
            context: nil
        )
        return CGSize(width: ceil(rect.width), height: ceil(rect.height))
    }
    
    private static func weightedFontName(
        name: FontFamily,
        weight: Font.Weight,
        design: Font.Design
    ) -> String {
        
        // Use exact name from map if available
        if let exactName = name.fontName(weight: weight) {
            return exactName
        }
        
        // Fallback design handling
        var baseName = name.rawValue
        switch design {
        case .rounded:
            baseName = "ArialRoundedMTBold" // System rounded fallback
        case .monospaced:
            baseName = "Courier"
        case .serif:
            baseName = "TimesNewRomanPSMT"
        default:
            break
        }
        
        let weightSuffix = weight.uiFontWeightSuffix
        return baseName + (weightSuffix.isEmpty ? "" : "-" + weightSuffix)
    }
}

private struct TestContentView: View {
    @State private var digit: String = "138"
    @State private var previewFontSize: CGFloat = 1000
    @State private var fontWeight: Font.Weight = .bold
    @State private var fontDesign: Font.Design = .rounded
    
    private var date: Date {
        let hours = ["13"].randomElement() ?? "08"
        let minutes = ["38"].randomElement() ?? "33"
        let timeString = "\(hours):\(minutes)"
        
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        let todayString = formatter.string(from: Date())
        let fullDateString = "\(todayString) \(timeString)"
        
        formatter.dateFormat = "yyyy-MM-dd HH:mm"
        return formatter.date(from: fullDateString) ?? Date()
    }
    
    var body: some View {
        let newDate = date
       return ScrollView {
            VStack(spacing: 20) {
                ForEach(FontFamily.allCases, id: \.rawValue) { (font: FontFamily) in
                    VStack {
                        Text(font.rawValue)
                            .font(Font.system(size: 16, weight: Font.Weight.bold))
                            .padding(.bottom, 5)
                        
                        TimeDisplayView(date: newDate,
                                        use24Hour: true,
                                        showSeconds: false,
                                        showAmPm: true,
                                        digitColor: .primary,
                                        glowIntensity: 0.5,
                                        manualScale: 1.0,
                                        stretched: false,
                                        clockOpacity: 1.0,
                                        fontFamily: font,
                                        fontWeight: fontWeight,
                                        fontDesign: fontDesign,
                                        forceHorizontalMode: true,
                                        isDisplayMode: false)

                        TimeSegment(
                            text: digit,
                            fontSize: .constant(129),      // CGFloat
                            opacity: 1.0,                  // Double
                            digitColor: Color.primary,     // Color
                            glowIntensity: 0.5,            // Double
                            fontFamily: font,              // FontFamily
                            fontWeight: fontWeight,
                            fontDesign: fontDesign,
                            isDisplayMode: false
                        )
                    }
                    .frame(width: 400, height: 200)
                    .border(Color.black)

                }
            }
            .padding()
        }
    }
}

struct FontCombinationsPreview: View {
    // All designs
    private let designs: [Font.Design] = Font.Design.allCases

    private let columns: [GridItem] = [
        GridItem(.flexible(), spacing: 20),
        GridItem(.flexible(), spacing: 20),
        GridItem(.flexible(), spacing: 20)
    ]

    var body: some View {
        // Precompute local copies to avoid type-checker stress
        let fonts: [FontFamily] = FontFamily.allCases.sorted {
            $0.rawValue.localizedCaseInsensitiveCompare($1.rawValue)
            == .orderedAscending
        }
        let designsLocal: [Font.Design] = designs

        return ScrollView {
            LazyVGrid(columns: columns, spacing: 20) {
                ForEach(fonts, id: \.self) { font in
                    ForEach(font.fontWeights, id: \.self) { weight in
                        ForEach(designsLocal, id: \.self) { design in
                            FontSampleCell(font: font, weight: weight, design: design)
                        }
                    }
                }
            }
            .padding()
        }
    }
}

private struct FontSampleCell: View {
    let font: FontFamily
    let weight: Font.Weight
    let design: Font.Design

    var body: some View {
        VStack(alignment: .center, spacing: 5) {
            Text("\(font.rawValue), \(weight.rawValue), \(design.rawValue)")
                .font(.system(size: 12, weight: .medium))
                .multilineTextAlignment(.center)
                .padding(.bottom, 5)
            TimeSegment(
                text: "38",
                fontSize: .constant(129),      // CGFloat
                opacity: 1.0,                  // Double
                digitColor: Color.primary,     // Color
                glowIntensity: 0.5,            // Double
                fontFamily: font,              // FontFamily
                fontWeight: weight,
                fontDesign: design,
                isDisplayMode: false)
                .frame(width: 100, height: 100)
                .border(Color.black)
        }
    }
}


#Preview {
    FontCombinationsPreview()
}


// MARK: - Descriptions for Font.Weight and Font.Design
private extension Font.Weight {
    var description: String {
        switch self {
        case .ultraLight: return "ultraLight"
        case .thin: return "thin"
        case .light: return "light"
        case .regular: return "regular"
        case .medium: return "medium"
        case .semibold: return "semibold"
        case .bold: return "bold"
        case .heavy: return "heavy"
        case .black: return "black"
        default:
            // Fallback for any future/unknown cases
            return "custom"
        }
    }
}

private extension Font.Design {
    var description: String {
        switch self {
        case .default: return "default"
        case .serif: return "serif"
        case .rounded: return "rounded"
        case .monospaced: return "monospaced"
        @unknown default:
            return "unknown"
        }
    }
}
