import SwiftUI
import UIKit

private final class VoiceRecordingFixtureComposerDelegate: NSObject, ComposerViewDelegate {
    func composerDidTapSend(_ composer: ComposerView) {}
    func composerDidTapAttach(_ composer: ComposerView) {}
    func composerTextDidChange(_ composer: ComposerView, text: String) {}
    func composerFocusDidChange(_ composer: ComposerView, isFocused: Bool) {}
    func composerHeightDidChange(_ composer: ComposerView, height: CGFloat) {}
    func composerDidCancelReply(_ composer: ComposerView) {}
    func composerDidCancelForward(_ composer: ComposerView) {}
    func composerUserDidType(_ composer: ComposerView) {}
    func composerKeyboardHeightDidChange(_ composer: ComposerView, height: CGFloat) {}
    func composerDidStartRecording(_ composer: ComposerView) {}
    func composerDidFinishRecording(_ composer: ComposerView, sendImmediately: Bool) {}
    func composerDidCancelRecording(_ composer: ComposerView) {}
    func composerDidLockRecording(_ composer: ComposerView) {}
}

private final class VoiceRecordingUITestFixtureContainer: UIView {
    enum Mode: String {
        case idle
        case armed
        case recordingUnlocked
        case locking30
        case locking70
        case cancelDrag
        case recordingLocked
        case stop
        case waitingPreview
        case preview
        case previewTrimmed
    }

    private let mode: Mode
    private let composer = ComposerView(frame: .zero)
    private let composerDelegate = VoiceRecordingFixtureComposerDelegate()
    private let stopTapMarker = UIView()

    private var previewPanel: RecordingPreviewPanel?
    private var recordingPanel: VoiceRecordingPanel?
    private var lockView: RecordingLockView?
    private var didSetup = false

    init(mode: Mode) {
        self.mode = mode
        super.init(frame: .zero)
        backgroundColor = .clear

        composer.delegate = composerDelegate
        composer.accessibilityIdentifier = "voice.fixture.composer"
        addSubview(composer)

        stopTapMarker.isHidden = true
        stopTapMarker.isAccessibilityElement = true
        stopTapMarker.accessibilityIdentifier = "voice.fixture.stopTapped"
        addSubview(stopTapMarker)
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) { fatalError() }

    override func layoutSubviews() {
        super.layoutSubviews()

        let composerHeight: CGFloat = 64
        composer.frame = CGRect(
            x: 0,
            y: bounds.height - composerHeight,
            width: bounds.width,
            height: composerHeight
        )
        stopTapMarker.frame = CGRect(x: 0, y: 0, width: 1, height: 1)

        guard !didSetup else { return }
        didSetup = true
        configureMode()
    }

    private func configureMode() {
        switch mode {
        case .idle:
            break
        case .armed:
            break
        case .recordingUnlocked:
            showRecordingPanel(locked: false)
        case .locking30:
            showRecordingPanel(locked: false)
            showLockView(lockness: 0.3, showStop: false)
        case .locking70:
            showRecordingPanel(locked: false)
            showLockView(lockness: 0.7, showStop: false)
        case .cancelDrag:
            showRecordingPanel(locked: false, cancelTranslation: -120)
        case .recordingLocked:
            showRecordingPanel(locked: true)
        case .stop:
            showRecordingPanel(locked: false)
            showLockView(lockness: 1.0, showStop: true)
        case .waitingPreview:
            showRecordingPanel(locked: true)
        case .preview:
            showPreviewPanel()
        case .previewTrimmed:
            showPreviewPanel()
        }
    }

    private func showRecordingPanel(locked: Bool, cancelTranslation: CGFloat = 0) {
        let panelWidth = max(220, bounds.width - 16 - 42 - 6 - 16)
        let panel = VoiceRecordingPanel(
            frame: CGRect(x: 16, y: bounds.height - 58, width: panelWidth, height: 42)
        )
        panel.updateDuration(95.78)
        panel.accessibilityIdentifier = "voice.fixture.recordingPanel"
        addSubview(panel)
        recordingPanel = panel

        if VoiceRecordingParityMath.shouldApplyCancelTransform(cancelTranslation) {
            panel.updateCancelTranslation(cancelTranslation)
        }

        if locked {
            panel.showCancelButton()
            showLockView(lockness: 1.0, showStop: true)

#if DEBUG
            DispatchQueue.main.async { [weak self] in
                self?.composer.debugSetRecordingStopAccessibilityAreaEnabled(true)
            }
#endif
        }
    }

    private func showLockView(lockness: CGFloat, showStop: Bool) {
        let lock = RecordingLockView(frame: CGRect(x: bounds.width - 58, y: bounds.height - 190, width: 40, height: 72))
        addSubview(lock)
        lock.updateLockness(lockness)
        if showStop {
            lock.showStopButton(onTap: { [weak self] in
                self?.stopTapMarker.isHidden = false
            })
        }
        lock.accessibilityIdentifier = "voice.fixture.lockView"
        lockView = lock
    }

    private func showPreviewPanel() {
        let tmpURL = FileManager.default.temporaryDirectory
            .appendingPathComponent("voice_recording_fixture.m4a")

        if !FileManager.default.fileExists(atPath: tmpURL.path) {
            FileManager.default.createFile(atPath: tmpURL.path, contents: Data(), attributes: nil)
        }

        let waveform = (0..<180).map { idx in
            let t = Double(idx) / 12.0
            return Float(abs(sin(t)))
        }
#if DEBUG
        composer.debugShowPreviewReplacingInputRow(
            fileURL: tmpURL,
            duration: 12.0,
            waveform: waveform
        )
#else
        let panelWidth = bounds.width - 32
        let panel = RecordingPreviewPanel(
            frame: CGRect(x: 16, y: bounds.height - 58, width: panelWidth, height: 42),
            fileURL: tmpURL,
            duration: 12.0,
            waveform: waveform
        )
        panel.accessibilityIdentifier = "voice.fixture.previewPanel"
        addSubview(panel)
        previewPanel = panel
#endif
    }
}

private struct VoiceRecordingUITestFixtureRepresentable: UIViewRepresentable {
    let mode: VoiceRecordingUITestFixtureContainer.Mode

    func makeUIView(context: Context) -> VoiceRecordingUITestFixtureContainer {
        let view = VoiceRecordingUITestFixtureContainer(mode: mode)
        view.accessibilityIdentifier = "voice.fixture.root"
        return view
    }

    func updateUIView(_ uiView: VoiceRecordingUITestFixtureContainer, context: Context) {}
}

struct VoiceRecordingUITestFixtureView: View {
    private let mode: VoiceRecordingUITestFixtureContainer.Mode

    init(modeRawValue: String) {
        self.mode = VoiceRecordingUITestFixtureContainer.Mode(rawValue: modeRawValue) ?? .idle
    }

    var body: some View {
        VStack(spacing: 12) {
            Text("Voice Recording Fixture")
                .font(.headline)
            Text("Mode: \(mode.rawValue)")
                .font(.footnote)
                .foregroundStyle(.secondary)
            VoiceRecordingUITestFixtureRepresentable(mode: mode)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
        .padding(.top, 24)
        .padding(.horizontal, 12)
        .background(Color(.systemBackground))
        .accessibilityIdentifier("voice.fixture.screen")
    }
}
