import AppKit
import AVFoundation
import CoreGraphics
import MastermindPOCCore

final class AppDelegate: NSObject, NSApplicationDelegate {
    private let settingsStore = OverlaySettingsStore()
    private lazy var overlayController = OverlayWindowController(
        initialSettings: settingsStore.settings,
        actions: OverlayActions(
            openSettings: { [weak self] in self?.showSettings() },
            hideOverlay: { [weak self] in self?.hideOverlay() },
            quitApp: { NSApplication.shared.terminate(nil) }
        )
    )
    private lazy var settingsWindowController = SettingsWindowController(settingsStore: settingsStore)
    private var stats = AudioPipelineStats()
    private var screenFrameCount = 0

    private lazy var captureCoordinator = CaptureCoordinator(
        onScreenFrame: { [weak self] frameCount in
            Task { @MainActor in
                self?.recordScreenFrame(frameCount)
            }
        },
        onSystemAudioFrame: { [weak self] frame in
            Task { @MainActor in
                self?.recordAudioFrame(frame)
            }
        },
        onError: { [weak self] message in
            Task { @MainActor in
                self?.setStatus(.error(message))
            }
        }
    )

    private lazy var microphoneEngine = MicrophoneCaptureEngine(
        onFrame: { [weak self] frame in
            Task { @MainActor in
                self?.recordAudioFrame(frame)
            }
        },
        onError: { [weak self] message in
            Task { @MainActor in
                self?.setStatus(.error(message))
            }
        }
    )

    private lazy var menuBarController = MenuBarController(
        actions: MenuBarController.Actions(
            showOverlay: { [weak self] in self?.showOverlay() },
            hideOverlay: { [weak self] in self?.hideOverlay() },
            openSettings: { [weak self] in self?.showSettings() },
            toggleClickThrough: { [weak self] in self?.toggleClickThrough() },
            startScreenAndSystemAudio: { [weak self] in self?.startScreenAndSystemAudio() },
            startMicrophone: { [weak self] in self?.startMicrophone() },
            pauseAllCapture: { [weak self] in self?.pauseAllCapture() },
            quit: { NSApplication.shared.terminate(nil) }
        )
    )

    func applicationDidFinishLaunching(_ notification: Notification) {
        settingsStore.onChange = { [weak self] settings in
            self?.overlayController.viewModel.backgroundOpacity = settings.backgroundOpacity
        }

        overlayController.show()
        setStatus(.idle)
        refreshCounters()
    }

    private func showOverlay() {
        overlayController.show()
        menuBarController.setOverlayVisible(true)
    }

    private func hideOverlay() {
        overlayController.hide()
        menuBarController.setOverlayVisible(false)
    }

    private func showSettings() {
        settingsWindowController.show()
    }

    private func toggleClickThrough() {
        let enabled = overlayController.toggleClickThrough()
        overlayController.viewModel.clickThroughEnabled = enabled
        menuBarController.setClickThrough(enabled)
    }

    private func startScreenAndSystemAudio() {
        Task {
            do {
                try await captureCoordinator.start(excludingWindowIDs: overlayController.excludedWindowIDs)
                setStatus(.screenContext)
            } catch {
                setStatus(.error(error.localizedDescription))
            }
        }
    }

    private func startMicrophone() {
        Task {
            do {
                try await requestMicrophoneAccess()
                try microphoneEngine.start()
                setStatus(.listening)
            } catch {
                setStatus(.error(error.localizedDescription))
            }
        }
    }

    private func pauseAllCapture() {
        Task {
            await captureCoordinator.stop()
            microphoneEngine.stop()
            setStatus(.paused)
        }
    }

    private func recordScreenFrame(_ frameCount: Int) {
        screenFrameCount = frameCount
        overlayController.viewModel.screenFrames = frameCount
        setStatus(.screenContext)
    }

    private func recordAudioFrame(_ frame: PCMFrame) {
        stats.recordFrame(source: frame.source, byteCount: frame.pcmS16LE.count)
        refreshCounters()

        switch frame.source {
        case .microphone:
            setStatus(.listening)
        case .system:
            setStatus(.systemAudio)
        }
    }

    private func refreshCounters() {
        overlayController.viewModel.microphoneFrames = stats.microphoneFrames
        overlayController.viewModel.microphoneBytes = stats.microphoneBytes
        overlayController.viewModel.systemFrames = stats.systemFrames
        overlayController.viewModel.systemBytes = stats.systemBytes
    }

    private func setStatus(_ status: TrustStatus) {
        overlayController.viewModel.apply(status: status)
        menuBarController.setStatus(status)
    }

    private func requestMicrophoneAccess() async throws {
        switch AVCaptureDevice.authorizationStatus(for: .audio) {
        case .authorized:
            return
        case .notDetermined:
            let granted = await AVCaptureDevice.requestAccess(for: .audio)
            if granted {
                return
            }
            throw POCError("Microphone permission was denied")
        case .denied, .restricted:
            throw POCError("Microphone permission is not available")
        @unknown default:
            throw POCError("Unknown microphone permission state")
        }
    }
}

struct POCError: LocalizedError {
    let message: String

    init(_ message: String) {
        self.message = message
    }

    var errorDescription: String? {
        message
    }
}
