import Foundation
import UIKit

// MARK: - Staff Renderer (iOS)

/// Draws the musical staff: 5 lines, clef, key signature, time signature, and bar lines.
/// UIKit port — identical drawing logic to macOS, with UIColor/UIFont instead of NSColor/NSFont.
struct StaffRenderer_iOS {
    let L = AppConstants.Layout.self

    func drawStaffLines(in context: CGContext, x: CGFloat, y: CGFloat, width: CGFloat) {
        context.setStrokeColor(UIColor.black.cgColor)
        context.setLineWidth(0.5)

        for i in 0..<5 {
            let lineY = y + CGFloat(i) * L.staffLineSpacing
            context.move(to: CGPoint(x: x, y: lineY))
            context.addLine(to: CGPoint(x: x + width, y: lineY))
        }
        context.strokePath()
    }

    func drawBarLine(in context: CGContext, x: CGFloat, y: CGFloat) {
        context.setStrokeColor(UIColor.black.cgColor)
        context.setLineWidth(L.barLineWidth)
        context.move(to: CGPoint(x: x, y: y))
        context.addLine(to: CGPoint(x: x, y: y + L.staffHeight))
        context.strokePath()
    }

    func drawDoubleBarLine(in context: CGContext, x: CGFloat, y: CGFloat) {
        context.setStrokeColor(UIColor.black.cgColor)

        context.setLineWidth(L.barLineWidth)
        context.move(to: CGPoint(x: x - 4, y: y))
        context.addLine(to: CGPoint(x: x - 4, y: y + L.staffHeight))
        context.strokePath()

        context.setLineWidth(L.barLineWidth * 3)
        context.move(to: CGPoint(x: x, y: y))
        context.addLine(to: CGPoint(x: x, y: y + L.staffHeight))
        context.strokePath()
    }

    func drawTrebleClef(in context: CGContext, x: CGFloat, y: CGFloat) {
        let font = UIFont.systemFont(ofSize: 32)
        let attrs: [NSAttributedString.Key: Any] = [
            .font: font,
            .foregroundColor: UIColor.black
        ]
        let clefStr = "\u{1D11E}" as NSString
        clefStr.draw(at: CGPoint(x: x, y: y - 8), withAttributes: attrs)
    }

    func drawBassClef(in context: CGContext, x: CGFloat, y: CGFloat) {
        let font = UIFont.systemFont(ofSize: 28)
        let attrs: [NSAttributedString.Key: Any] = [
            .font: font,
            .foregroundColor: UIColor.black
        ]
        let clefStr = "\u{1D122}" as NSString
        clefStr.draw(at: CGPoint(x: x, y: y - 4), withAttributes: attrs)
    }

    func drawKeySignature(
        in context: CGContext,
        keySignature: KeySignature,
        x: CGFloat,
        y: CGFloat
    ) -> CGFloat {
        var currentX = x
        let font = UIFont.systemFont(ofSize: 16)

        let symbol = keySignature.usesSharps ? "\u{266F}" : "\u{266D}"
        let color = UIColor.black

        let sharpPositions: [Pitch.NoteName: CGFloat] = [
            .F: 0, .C: 3, .G: -0.5, .D: 2.5, .A: -1, .E: 2, .B: -1.5
        ]
        let flatPositions: [Pitch.NoteName: CGFloat] = [
            .B: 1, .E: -1.5, .A: 1.5, .D: -1, .G: 2, .C: -0.5, .F: 2.5
        ]

        let positions = keySignature.usesSharps ? sharpPositions : flatPositions

        for noteName in keySignature.sharpsAndFlats {
            if let staffPos = positions[noteName] {
                let noteY = y + staffPos * L.staffLineSpacing
                let attrs: [NSAttributedString.Key: Any] = [
                    .font: font,
                    .foregroundColor: color
                ]
                (symbol as NSString).draw(at: CGPoint(x: currentX, y: noteY - 6), withAttributes: attrs)
                currentX += 10
            }
        }

        return currentX
    }

    func drawTimeSignature(
        in context: CGContext,
        timeSignature: TimeSignature,
        x: CGFloat,
        y: CGFloat
    ) {
        let font = UIFont.boldSystemFont(ofSize: 18)
        let attrs: [NSAttributedString.Key: Any] = [
            .font: font,
            .foregroundColor: UIColor.black
        ]

        let topStr = "\(timeSignature.beatsPerMeasure)" as NSString
        let bottomStr = "\(timeSignature.noteValue)" as NSString

        topStr.draw(at: CGPoint(x: x, y: y - 2), withAttributes: attrs)
        bottomStr.draw(at: CGPoint(x: x, y: y + L.staffLineSpacing * 2 - 2), withAttributes: attrs)
    }

    func drawLedgerLines(
        in context: CGContext,
        noteY: CGFloat,
        staffTopY: CGFloat,
        noteX: CGFloat
    ) {
        let staffBottomY = staffTopY + L.staffHeight
        let ext = L.ledgerLineExtension

        context.setStrokeColor(UIColor.black.cgColor)
        context.setLineWidth(0.5)

        if noteY < staffTopY {
            var y = staffTopY - L.staffLineSpacing
            while y >= noteY - L.staffLineSpacing / 2 {
                context.move(to: CGPoint(x: noteX - ext, y: y))
                context.addLine(to: CGPoint(x: noteX + L.noteHeadWidth + ext, y: y))
                y -= L.staffLineSpacing
            }
        } else if noteY > staffBottomY {
            var y = staffBottomY + L.staffLineSpacing
            while y <= noteY + L.staffLineSpacing / 2 {
                context.move(to: CGPoint(x: noteX - ext, y: y))
                context.addLine(to: CGPoint(x: noteX + L.noteHeadWidth + ext, y: y))
                y += L.staffLineSpacing
            }
        }

        context.strokePath()
    }
}
