//
//  SQButton.swift
//
//
//  Created by Victor on 12/06/2024.
//

import Lottie
import SwiftUI

struct SQButton: View {
    let title: String
    let action: () -> Void

    @State private var type: SQButtonType = .solid
    @State private var colorScheme: SQButtonColorScheme = .neutral
    @State private var textSize: CGFloat = 16
    @State private var font: SQTextFont = .semiBold
    @State private var icon: SQIcon? = nil
    @State private var isPressed: Bool = false
    @State private var isLarge: Bool = false

    @Binding var isLoading: Bool

    @Environment(\.isEnabled) private var isEnabled

    private var textWidth: CGFloat {
        let font = UIFont.systemFont(ofSize: textSize)
        let attributes = [NSAttributedString.Key.font: font]
        let size = (title as NSString).size(withAttributes: attributes)
        return size.width + (icon != nil ? 24 : 0)
    }

    init(_ title: String,
         isLoading: Binding<Bool> = .constant(false),
         action: @escaping () -> Void)
    {
        self.title = title
        self._isLoading = isLoading
        self.action = action
    }

    private var buttonStyle: SQButtonStyle {
        SQButtonStyle(
            type: type,
            colorScheme: colorScheme,
            isLoading: isLoading,
            isDisabled: !isEnabled,
            isPressed: isPressed
        )
    }

    var body: some View {
        Button(action: {
            if !isLoading, !isEnabled {
                action()
            }
        }, label: {
            HStack {
                if isLoading {
                    LottieView(animation: .named("av_loader"))
                        .looping()
                        .frame(width: 20)
                } else {
                    if icon != nil {
                        icon
                            .foregroundColor(buttonStyle.textColor)
                    }

                    SQText(title)
                        .sqSize(textSize)
                        .sqFont(font)
                        .sqColor(buttonStyle.textColor)
                }
            }
            .frame(minWidth: textWidth)
            .frame(maxWidth: isLarge ? .infinity : nil, alignment: .center)
            .padding(.horizontal, 30)
            .padding(.vertical, 12)
            .frame(height: 40, alignment: .center)
            .background(buttonStyle.backgroundColor)
            .cornerRadius(100)
            .overlay(
                RoundedRectangle(cornerRadius: 100)
                    .inset(by: 0.5)
                    .stroke(buttonStyle.borderColor, lineWidth: 1)
            )
        })
        .buttonStyle(PressedButtonStyle(isPressed: $isPressed))
    }
}

struct PressedButtonStyle: ButtonStyle {
    @Binding var isPressed: Bool

    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .onChange(of: configuration.isPressed) { newValue in
                isPressed = newValue
            }
    }
}

// MARK: - Modifiers

extension SQButton {
    func sqButtonType(_ type: SQButtonType) -> SQButton {
        var copy = self
        copy._type = State(initialValue: type)
        return copy
    }

    func sqColorScheme(_ scheme: SQButtonColorScheme) -> SQButton {
        var copy = self
        copy._colorScheme = State(initialValue: scheme)
        return copy
    }

    func sqTextSize(_ size: CGFloat) -> SQButton {
        var copy = self
        copy._textSize = State(initialValue: size)
        return copy
    }

    func sqFont(_ font: SQTextFont) -> SQButton {
        var copy = self
        copy._font = State(initialValue: font)
        return copy
    }

    func sqIcon(_ icon: SQIcon?) -> SQButton {
        var copy = self
        copy._icon = State(initialValue: icon)
        return copy
    }

    func sqLarge(_ isLarge: Bool = true) -> SQButton {
        var copy = self
        copy._isLarge = State(initialValue: isLarge)
        return copy
    }
}

// MARK: - Properties

enum SQButtonType: String, CaseIterable {
    case solid
    case line
    case light
    case glass
}

enum SQButtonColorScheme: String, CaseIterable {
    case neutral
    case green
    case pink
    case blue
    case yellow
    case gold
    case orange
    case red
    case grape
    case forest
    case royal
    case white

    var baseColor: Color {
        switch self {
        case .neutral:
            return .sqNeutral(100)
        case .green:
            return .sqGreen(60)
        case .pink:
            return .sqPink(60)
        case .blue:
            return .sqBlue(50)
        case .yellow:
            return .sqYellow(50)
        case .gold:
            return .sqGold(50)
        case .orange:
            return .sqOrange(50)
        case .red:
            return .sqRed(60)
        case .grape:
            return .sqGrape(80)
        case .forest:
            return .sqForest(100)
        case .royal:
            return .sqRoyal(60)
        case .white:
            return .white
        }
    }

    var mediumColor: Color {
        switch self {
        case .neutral:
            return .sqNeutral(30)
        case .green:
            return .sqGreen(30)
        case .pink:
            return .sqPink(30)
        case .blue:
            return .sqBlue(30)
        case .yellow:
            return .sqYellow(30)
        case .gold:
            return .sqGold(30)
        case .orange:
            return .sqOrange(30)
        case .red:
            return .sqRed(10)
        case .grape:
            return .sqGrape(30)
        case .forest:
            return .sqForest(50)
        case .royal:
            return .sqRoyal(30)
        case .white:
            return .white
        }
    }

    var lightColor: Color {
        switch self {
        case .neutral:
            return .sqNeutral(15)
        case .green:
            return .sqGreen(10)
        case .pink:
            return .sqPink(10)
        case .blue:
            return .sqBlue(10)
        case .yellow:
            return .sqYellow(10)
        case .gold:
            return .sqGold(10)
        case .orange:
            return .sqOrange(10)
        case .red:
            return .sqRed(10)
        case .grape:
            return .sqGrape(10)
        case .forest:
            return .sqForest(10)
        case .royal:
            return .sqRoyal(10)
        case .white:
            return .white
        }
    }
}

struct SQButtonStyle {
    let type: SQButtonType
    let colorScheme: SQButtonColorScheme
    let isLoading: Bool
    let isDisabled: Bool
    let isPressed: Bool

    var backgroundColor: Color {
        if isPressed && !isDisabled && !isLoading {
            switch type {
            case .solid:
                return colorScheme.baseColor.opacity(0.8)
            case .line:
                return .clear
            case .light:
                return colorScheme.lightColor
            case .glass:
                return .clear
            }
        }

        if isDisabled {
            switch type {
            case .solid:
                return colorScheme.mediumColor
            case .line:
                return .clear
            case .light:
                return colorScheme.lightColor
            case .glass:
                return .clear
            }
        }

        if isLoading {
            switch type {
            case .solid:
                return colorScheme.mediumColor
            case .line:
                return .clear
            case .light:
                return colorScheme.lightColor
            case .glass:
                return .clear
            }
        }

        switch type {
        case .solid:
            return colorScheme.baseColor
        case .line:
            return .clear
        case .light:
            return colorScheme.lightColor
        case .glass:
            return .clear
        }
    }

    var borderColor: Color {
        switch type {
        case .solid:
            if isPressed && !isDisabled && !isLoading {
                return colorScheme.baseColor.opacity(0.8)
            }

            if isDisabled {
                return colorScheme.lightColor.opacity(0.5)
            }

            if isLoading {
                return colorScheme.lightColor.opacity(0.8)
            }

        case .line:
            if isPressed && !isDisabled && !isLoading {
                return colorScheme.baseColor.opacity(0.8)
            }

            if isDisabled {
                return colorScheme.mediumColor
            }

            if isLoading {
                return colorScheme.mediumColor
            }

            return colorScheme.baseColor

        case .light:
            if isPressed && !isDisabled && !isLoading {
                return colorScheme.lightColor.opacity(0.8)
            }

            if isDisabled {
                return colorScheme.lightColor.opacity(0.5)
            }

            if isLoading {
                return colorScheme.lightColor.opacity(0.8)
            }

            return colorScheme.lightColor

        case .glass:
            return .clear
        }

        return colorScheme.baseColor
    }

    var textColor: Color {
        if isPressed && !isDisabled && !isLoading {
            switch type {
            case .solid:
                return .white
            case .line, .light, .glass:
                return colorScheme.baseColor.opacity(0.8)
            }
        }

        if isDisabled {
            switch type {
            case .solid:
                return .white
            case .line, .light, .glass:
                return colorScheme.mediumColor
            }
        }

        switch type {
        case .solid:
            return .white
        case .line, .light, .glass:
            return colorScheme.baseColor
        }
    }
}

#Preview {
    VStack(spacing: 32) {
        HStack {
            VStack(spacing: 16) {
                SQButton("C'est parti !") {}
                    .sqColorScheme(.royal)
                SQButton("C'est parti !") {}
                    .sqColorScheme(.royal)
                    .sqButtonType(.line)
                SQButton("C'est parti !") {}
                    .sqColorScheme(.royal)
                    .sqButtonType(.light)
                SQButton("C'est parti !") {}
                    .sqColorScheme(.royal)
                    .sqButtonType(.glass)
            }
            VStack(spacing: 16) {
                SQButton("C'est parti !", isLoading: .constant(true)) {}
                    .sqColorScheme(.royal)
                SQButton("C'est parti !", isLoading: .constant(true)) {}
                    .sqColorScheme(.royal)
                    .sqButtonType(.line)
                SQButton("C'est parti !", isLoading: .constant(true)) {}
                    .sqColorScheme(.royal)
                    .sqButtonType(.light)
                SQButton("C'est parti !", isLoading: .constant(true)) {}
                    .sqColorScheme(.royal)
                    .sqButtonType(.glass)
            }
        }

        SQButton("Continuer avec Apple") {}
            .sqButtonType(.line)
            .sqIcon(SQIcon(.apple_brand))
            .sqLarge()
    }
    .padding()
}

