//
//  FortuneWheelView.swift
//  PadelClub
//
//  Created by Razmig Sarkissian on 22/04/2024.
//

import SwiftUI

protocol SpinDrawable {
    func segmentLabel(_ displayStyle: DisplayStyle) -> [String]
}

extension String: SpinDrawable {
    func segmentLabel(_ displayStyle: DisplayStyle) -> [String] {
        [self]
    }
}

extension Match: SpinDrawable {
    func segmentLabel(_ displayStyle: DisplayStyle) -> [String] {
        let teams = teams()
        if teams.count == 1 {
            return teams.first!.segmentLabel(displayStyle)
        } else {
            return [roundTitle(), matchTitle(displayStyle)].compactMap { $0 }
        }
    }
}

extension TeamRegistration: SpinDrawable {
    func segmentLabel(_ displayStyle: DisplayStyle) -> [String] {
        var strings: [String] = []
        let indexLabel = tournamentObject()?.labelIndexOf(team: self)
        if let indexLabel {
            strings.append(indexLabel)
        }
        strings.append(contentsOf: self.players().map { $0.playerLabel(displayStyle) })
        return strings
    }
}

struct DrawResult: Identifiable {
    let id: UUID = UUID()
    let drawee: Int
    let drawIndex: Int
}

struct DrawOption: Identifiable, SpinDrawable {
    let id: UUID = UUID()
    let initialIndex: Int
    let option: SpinDrawable
    
    func segmentLabel(_ displayStyle: DisplayStyle) -> [String] {
        option.segmentLabel(displayStyle)
    }
}

struct SpinDrawView: View {
    @Environment(\.dismiss) private var dismiss

    let drawees: [any SpinDrawable]
    @State var segments: [any SpinDrawable]
    var autoMode: Bool = false
    let completion: ([DrawResult]) async -> Void // Completion closure
    
    @State private var drawCount: Int = 0
    @State private var draws: [DrawResult] = [DrawResult]()
    @State private var drawOptions: [DrawOption] = [DrawOption]()
    @State private var selectedIndex: Int?
    @State private var disabled: Bool = false
    
    var body: some View {
        List {
            if selectedIndex != nil {
                Section {
                    _validationLabelView(drawee: drawCount, result: segments[draws.last!.drawIndex])
                    if autoMode == false || drawCount == drawees.count {
                        RowButtonView("Valider le tirage") {
                            await completion(draws)
                            dismiss()
                        }
                    } else {
                        Text("Prochain tirage en préparation")
                    }
                }
            } else if drawCount < drawees.count {
                Section {
                    _segmentLabelView(segment: drawees[drawCount].segmentLabel(.wide), horizontalAlignment: .center)
                }
                
                Section {
                    ZStack {
                        FortuneWheelContainerView(segments: drawOptions, autoMode: autoMode) { index in
                            self.selectedIndex = index
                            self.draws.append(DrawResult(drawee: drawCount, drawIndex: drawOptions[index].initialIndex))
                            self.drawOptions.remove(at: index)
                            
                            if autoMode && drawCount < drawees.count {
                                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                                    self.drawCount += 1
                                    if drawOptions.count == 1 {
                                        self.draws.append(DrawResult(drawee: self.drawCount, drawIndex: self.drawOptions[0].initialIndex))
                                        self.drawOptions.remove(at: 0)
                                        self.drawCount += 1
                                        self.selectedIndex = nil
                                    } else {
                                        self.selectedIndex = nil
                                    }
                                }
                            }
                        }
                        .simultaneousGesture(
                            DragGesture().onChanged({ (value) in
                                disabled = true
                            }).onEnded({ (value) in
                            })
                        )
                        Rectangle()
                            .fill(.white.opacity(0.01))
                            .clipShape(Circle())
                            .allowsHitTesting(disabled)
                    }
                    .listRowBackground(Color.clear)
                    .listRowSeparator(.hidden)
                } footer: {
                    HStack {
                        Spacer()
                        if autoMode {
                            Text("Mode automatique")
                        } else {
                            Text("Lancer la roue en glissant avec le doigt").multilineTextAlignment(.center)
                        }
                        Spacer()
                    }
                }
            } else {
                Section {
                    Text("Tous les tirages sont terminés")
                    ForEach(draws) { drawResult in
                        _validationLabelView(drawee: drawResult.drawee, result: segments[drawResult.drawIndex])
                    }
                }
                
                RowButtonView("Valider les tirages") {
                    await completion(draws)
                    dismiss()
                }
            }
  
            //todo
//            Section {
//                Text("XXX")
//                Text("XXX")
//                Text("XXX")
//            } header: {
//                Text("Comité du tournoi")
//            }
        }
        .toolbar {
            ToolbarItem(placement: .cancellationAction) {
                Button("Annuler", role: .cancel) {
                    dismiss()
                }
                .disabled(disabled || autoMode)
            }
        }
        .navigationBarBackButtonHidden()
        .navigationTitle("Tirage au sort")
        .navigationBarTitleDisplayMode(.inline)
        .toolbarBackground(.visible, for: .navigationBar)
        .toolbar(.hidden, for: .tabBar)
        .listStyle(.insetGrouped)
        .scrollDisabled(true)
        .interactiveDismissDisabled()
        .onAppear {
            for (index, segment) in segments.enumerated() {
                drawOptions.append(DrawOption(initialIndex: index, option: segment))
            }
        }
    }
    
    
    private func _segmentLabelView(segment: [String], horizontalAlignment: HorizontalAlignment = .leading) -> some View {
        VStack(alignment: horizontalAlignment, spacing: 0.0) {
            ForEach(segment, id: \.self) { string in
                Text(string).font(.title3)
                    .frame(maxWidth: .infinity)
                    .lineLimit(1)
            }
        }
    }

    @ViewBuilder
    private func _validationLabelView(drawee: Int, result: SpinDrawable) -> some View {
        VStack(spacing: 0.0) {
            let draw = drawees[drawee]
            _segmentLabelView(segment: draw.segmentLabel(.wide), horizontalAlignment: .center)
            if result as? TeamRegistration != nil {
                Image(systemName: "flag.2.crossed.fill").font(.largeTitle).foregroundColor(.logoRed)
            } else {
                Image(systemName: "arrowshape.down.fill").font(.largeTitle).foregroundColor(.logoRed)
            }
            _segmentLabelView(segment: result.segmentLabel(.wide), horizontalAlignment: .center)
        }
    }
}

struct FortuneWheelContainerView: View {
    @State private var rotation: Double = 0
    let segments: [any SpinDrawable]
    let autoMode: Bool
    let completion: (Int) -> Void // Completion closure

    var body: some View {
        FortuneWheelView(segments: segments)
            .rotationEffect(.degrees(rotation))
            .aspectRatio(contentMode: .fill)
            .padding(.top, 5)
            .overlay(alignment: .top) {
                Triangle()
                    .fill(Color.red)
                    .stroke(Color.black, lineWidth: 2)
                    .frame(width: 20, height: 20)
                    .rotationEffect(.degrees(180))
            }
            .onAppear {
                if autoMode {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                        rotation = 0
                        rollWheel()
                    }
                }
            }
            .gesture(
                DragGesture().onChanged({ (value) in
                    if value.translation.width < 0 {
                        rotation = Double(-value.translation.width)
                    }
                }).onEnded({ (value) in
                    rollWheel()
                })
            )
    }
    
    func rollWheel() {
        //rotation = 0
        
        // Generate a random angle for the wheel to rotate
        let randomAngle = Double.random(in: 1440...2880) // Adjust range for more or less rotations
        let duration = Double.random(in: 2...4)

        // Apply rotation animation with ease-out
        withAnimation(.easeOut(duration: duration)) {
            rotation += randomAngle
        }
        
        
        // Calculate the angle between the top center and the current rotation position
        let segmentAngle = 360.0 / Double(segments.count)
        let arrowAngle = 270.0 // Angle of the arrow at the top center of the wheel
        let normalizedRotation = (rotation + 360).truncatingRemainder(dividingBy: 360)
        let angleToTopCenter = (arrowAngle - normalizedRotation + 360).truncatingRemainder(dividingBy: 360)
        
        // Determine the selected segment based on the angle
        let index = Int(angleToTopCenter / segmentAngle)
        
        DispatchQueue.main.asyncAfter(deadline: .now() + duration + 1) {
            let selectedSegment = index < 0 ? segments.count + index : index // Normalize index
            completion(selectedSegment)
        }
    }



}

struct FortuneWheelView: View {
    let segments: [any SpinDrawable]
    let colors: [Color] = [.yellow, .cyan, .green, .blue, .orange, .purple, .mint, .brown]
    
    func getColor(forIndex index: Int) -> Color {
        if index < colors.count {
            return colors[index]
        }
        
        let level = Double(index)/Double(colors.count) / 100
        let modulo = colors[index%colors.count].variation(withHueOffset: level)
        
        return modulo
    }
    
    var body: some View {
        GeometryReader { proxy in
            let radius = proxy.size.width / 2
            ZStack {
                ForEach(segments.indices, id: \.self) { index in
                    Path { path in
                        let segmentAngle = 360.0 / Double(segments.count)
                        let startAngle = Angle(degrees: Double(index) * segmentAngle)
                        let endAngle = Angle(degrees: Double(index + 1) * segmentAngle)
                        let center = CGPoint(x: radius, y: radius)
                        path.move(to: center)
                        path.addArc(center: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: false)
                        path.closeSubpath()
                    }
                    .fill(getColor(forIndex:index))
                    
                    VStack(alignment: .trailing, spacing: 0.0) {
                        let strings = segments[index].segmentLabel(.short)
                        ForEach(strings, id: \.self) { string in
                            Text(string).bold()
                        }
                    }
                    .padding(.trailing, 40)
                    .rotationEffect(.degrees(Double(index) * (360 / Double(segments.count)) + (360 / Double(segments.count) / 2)))
                    .foregroundColor(.white)
                    .position(arcPosition(index: index, radius: radius))
                }
            }
        }
    }
    
    // Calculate the position for the text in the middle of the arc segment
    private func arcPosition(index: Int, radius: Double) -> CGPoint {
        let segmentAngle = 360.0 / Double(segments.count)
        let startAngle = Double(index) * segmentAngle
        let endAngle = Double(index + 1) * segmentAngle
        let centerAngle = (startAngle + endAngle) / 2
        let adjustedRadius = radius - 20.0
        let x = radius + (adjustedRadius - 30) * cos(centerAngle * .pi / 180) // Adjusted radius for better fit
        let y = radius + (adjustedRadius - 30) * sin(centerAngle * .pi / 180) // Adjusted radius for better fit
        return CGPoint(x: x, y: y)
    }
}

struct Triangle: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        path.move(to: CGPoint(x: rect.midX, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        path.closeSubpath()
        return path
    }
}

//#Preview {
//    SpinDrawView(drawees: ["3", "4"], segments: ["1", "2"]) { draws in
//    }
//}
