import SwiftUI

public func scaleSize(_ size: CGFloat, _ scaleRate: CGFloat? = nil) -> CGFloat {
    let defaultScreenSize: CGFloat = 375
    let maxFontScale: CGFloat = scaleRate ?? 1.5
    let maxDeviceScale: CGFloat = 5

    let deviceWidth = UIScreen.main.bounds.width
    let deviceScale = deviceWidth / defaultScreenSize

    let defaultFont = UIFont.systemFont(ofSize: UIFont.labelFontSize)
    let scaledFont = UIFontMetrics.default.scaledFont(for: defaultFont)
    let fontScale = scaledFont.pointSize / defaultFont.pointSize

    var fontSizeDeviceScale = size
    var fontSizeOSScale = size


    if deviceScale > 1 {
        fontSizeDeviceScale = min(fontSizeDeviceScale * deviceScale, fontSizeDeviceScale + maxDeviceScale)
    }

    if fontScale > 1 {
        fontSizeOSScale = min(fontSizeOSScale * fontScale, fontSizeOSScale * maxFontScale)
    }

    return max(fontSizeDeviceScale, fontSizeOSScale)
}

public enum TypographyStyle {
    case headlineDefaultBold
    case headerMBold
    case headerDefaultBold
    case headerSSemibold
    case headerXsSemibold
    case bodyDefaultRegular
    case bodyDefaultRegularStrikethrough
    case descriptionDefaultRegular
    case descriptionDefaultRegularStrikethrough
    case descriptionXsRegular
    case descriptionXsRegularStrikethrough
    case labelDefaultMedium
    case labelSMedium
    case labelXsMedium
    case actionDefaultBold
    case actionSBold
    case actionXsBold
    case actionXxsBold
}

public extension TypographyStyle {
    var fontSize: CGFloat {
        switch self {
        case .headlineDefaultBold: return 24
        case .headerMBold: return 18
        case .headerDefaultBold: return 16
        case .headerSSemibold: return 14
        case .headerXsSemibold: return 12
        case .bodyDefaultRegular, .bodyDefaultRegularStrikethrough: return 14
        case .descriptionDefaultRegular, .descriptionDefaultRegularStrikethrough: return 12
        case .descriptionXsRegular, .descriptionXsRegularStrikethrough: return 10
        case .labelDefaultMedium: return 14
        case .labelSMedium: return 12
        case .labelXsMedium: return 10
        case .actionDefaultBold: return 16
        case .actionSBold: return 14
        case .actionXsBold: return 12
        case .actionXxsBold: return 10
        }
    }
    var lineHeight: CGFloat {
        switch self {
        case .headlineDefaultBold: return 34
        case .headerMBold: return 26
        case .headerDefaultBold: return 22
        case .headerSSemibold: return 20
        case .headerXsSemibold: return 18
        case .bodyDefaultRegular, .bodyDefaultRegularStrikethrough: return 20
        case .descriptionDefaultRegular, .descriptionDefaultRegularStrikethrough: return 18
        case .descriptionXsRegular, .descriptionXsRegularStrikethrough: return 14
        case .labelDefaultMedium: return 20
        case .labelSMedium: return 18
        case .labelXsMedium: return 14
        case .actionDefaultBold: return 22
        case .actionSBold: return 20
        case .actionXsBold: return 18
        case .actionXxsBold: return 14
        }
    }
    var fontWeight: Font.Weight {
        switch self {
        case .headlineDefaultBold, .headerMBold, .headerDefaultBold,
                .actionDefaultBold, .actionSBold, .actionXsBold, .actionXxsBold:
            return .bold
        case .headerSSemibold, .headerXsSemibold:
            return .semibold
        case .bodyDefaultRegular, .bodyDefaultRegularStrikethrough,
                .descriptionDefaultRegular, .descriptionDefaultRegularStrikethrough,
                .descriptionXsRegular, .descriptionXsRegularStrikethrough:
            return .regular
        case .labelDefaultMedium, .labelSMedium, .labelXsMedium:
            return .medium
        }
    }
    var isStrikethrough: Bool {
        switch self {
        case .bodyDefaultRegularStrikethrough,
                .descriptionDefaultRegularStrikethrough,
                .descriptionXsRegularStrikethrough:
            return true
        default:
            return false
        }
    }
}

public struct MomoText: View {
    private let content: String
    private let typography: TypographyStyle
    private let color: Color

    public init(
        _ content: String,
        typography: TypographyStyle = .bodyDefaultRegular,
        color: Color = Colors.text
    ) {
        self.content = content
        self.typography = typography
        self.color = color
    }

    public var body: some View {
        let text = SwiftUI.Text(content)
            .font(.system(size: scaleSize(typography.fontSize), weight: typography.fontWeight))
            .foregroundColor(color)
            .lineSpacing(scaleSize(typography.lineHeight) - scaleSize(typography.fontSize))

        return text
    }
}
