import SwiftUI
import MusicModel
import AudioCore

/// One song: score, mixer, transport — the whole record-a-part loop.
struct ProjectView: View {
    @State private var model: ProjectModel
    let onClose: () -> Void

    @State private var takeSheetPart: String?
    @State private var showSettings = false
    @State private var showExport = false
    @AppStorage("didShowHeadphonesTip") private var didShowHeadphonesTip = false
    @State private var showHeadphonesTip = false

    init(store: ProjectStore, onClose: @escaping () -> Void) {
        _model = State(initialValue: ProjectModel(store: store))
        self.onClose = onClose
    }

    var body: some View {
        NavigationStack {
            VStack(spacing: 0) {
                ScoreScrollView(
                    score: model.score,
                    highlightedPartIndex: recordingPartIndex,
                    selectedMeasures: model.selectedMeasures,
                    tickProvider: { [weak model] in model?.cursorTick() },
                    autoScroll: model.isPlaying,
                    onMeasureTapped: { model.measureTapped($0) }
                )

                if case .recording = model.recordPhase {
                    PitchNeedle(model: model)
                }

                if let toast = model.toast {
                    Button {
                        model.undoLastTake()
                    } label: {
                        Label(toast, systemImage: "arrow.uturn.backward")
                            .font(.callout)
                            .frame(maxWidth: .infinity)
                            .padding(.vertical, 8)
                            .background(.yellow.opacity(0.2))
                    }
                    .buttonStyle(.plain)
                    .transition(.move(edge: .bottom))
                }

                if !model.mismatchedTakeParts.isEmpty {
                    Text("Takes for \(model.mismatchedTakeParts.joined(separator: ", ")) were recorded at a different tempo and are muted")
                        .font(.caption2)
                        .foregroundStyle(.orange)
                        .padding(.vertical, 4)
                }

                Divider()
                MixerStrip(model: model, onPartDetail: { takeSheetPart = $0 })
                Divider()
                TransportBar(model: model, onSettings: { showSettings = true })
            }
            .navigationTitle(model.score.title)
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Button("Done") {
                        model.shutdown()
                        onClose()
                    }
                }
                ToolbarItem(placement: .topBarTrailing) {
                    Button {
                        showExport = true
                    } label: {
                        Image(systemName: "square.and.arrow.up")
                    }
                    .disabled(model.recordPhase != .idle)
                }
            }
            .sheet(item: $takeSheetPart) { part in
                TakeSheet(model: model, partName: part)
                    .presentationDetents([.medium, .large])
            }
            .sheet(isPresented: $showSettings) {
                SettingsSheet(model: model)
                    .presentationDetents([.medium])
            }
            .sheet(isPresented: $showExport) {
                ExportSheet(model: model)
                    .presentationDetents([.medium, .large])
            }
            .alert("Error", isPresented: .init(
                get: { model.errorMessage != nil },
                set: { if !$0 { model.errorMessage = nil } }
            )) {
                Button("OK") { model.errorMessage = nil }
            } message: {
                Text(model.errorMessage ?? "")
            }
            .alert("Wear headphones", isPresented: $showHeadphonesTip) {
                Button("Got it") { didShowHeadphonesTip = true }
            } message: {
                Text("When you record a part, the other parts play in your headphones while the mic records only your voice. Without headphones they'd bleed into the recording.")
            }
            .onAppear {
                if !didShowHeadphonesTip { showHeadphonesTip = true }
            }
        }
        .interactiveDismissDisabled()
    }

    private var recordingPartIndex: Int? {
        if case .recording(let name) = model.recordPhase {
            return model.score.parts.firstIndex { $0.name == name }
        }
        return nil
    }
}

extension String: @retroactive Identifiable {
    public var id: String { self }
}
