import AVFoundation
import SwiftUI

// MARK: - CameraPreviewView

/// Live camera preview using AVCaptureSession, wrapped for SwiftUI.
///
/// Figma: Camera tile in attachment panel shows a real-time rear camera feed.
/// Uses `.medium` preset for minimal memory/battery usage (it's just a preview).
///
/// Graceful fallback: on Simulator or when camera unavailable, shows a dark
/// placeholder with a camera icon.
struct CameraPreviewView: UIViewRepresentable {

    func makeUIView(context: Context) -> CameraPreviewUIView {
        let view = CameraPreviewUIView()
        return view
    }

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

    static func dismantleUIView(_ uiView: CameraPreviewUIView, coordinator: ()) {
        uiView.stopSession()
    }
}

// MARK: - CameraPreviewUIView

/// UIKit view hosting AVCaptureVideoPreviewLayer for live camera feed.
///
/// Permission request is deferred to `didMoveToWindow()` — the system dialog
/// needs an active window to present on. Requesting in `init()` is too early.
final class CameraPreviewUIView: UIView {

    private let captureSession = AVCaptureSession()
    private var previewLayer: AVCaptureVideoPreviewLayer?
    private var isSessionRunning = false
    private var isSetUp = false

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(white: 0.08, alpha: 1)
        clipsToBounds = true
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        previewLayer?.frame = bounds
    }

    override func didMoveToWindow() {
        super.didMoveToWindow()
        if window != nil {
            // First time: request permission + set up session
            // Subsequent times: just resume
            if !isSetUp {
                isSetUp = true
                requestAccessAndSetup()
            } else {
                startSession()
            }
        } else {
            stopSession()
        }
    }

    // MARK: - Permission + Session Setup

    private func requestAccessAndSetup() {
        #if targetEnvironment(simulator)
        addPlaceholder()
        return
        #else
        switch AVCaptureDevice.authorizationStatus(for: .video) {
        case .authorized:
            configureSession()
        case .notDetermined:
            // System dialog will present over the current window
            AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in
                DispatchQueue.main.async {
                    if granted {
                        self?.configureSession()
                    } else {
                        self?.addDeniedPlaceholder()
                    }
                }
            }
        default:
            addDeniedPlaceholder()
        }
        #endif
    }

    /// Configures AVCaptureSession with rear camera input + preview layer.
    /// Called only after camera authorization is confirmed.
    private func configureSession() {
        guard let device = AVCaptureDevice.default(
            .builtInWideAngleCamera, for: .video, position: .back
        ) else {
            addPlaceholder()
            return
        }

        do {
            let input = try AVCaptureDeviceInput(device: device)
            captureSession.beginConfiguration()
            captureSession.sessionPreset = .medium
            if captureSession.canAddInput(input) {
                captureSession.addInput(input)
            }
            captureSession.commitConfiguration()

            let preview = AVCaptureVideoPreviewLayer(session: captureSession)
            preview.videoGravity = .resizeAspectFill
            preview.frame = bounds
            layer.addSublayer(preview)
            previewLayer = preview

            startSession()
        } catch {
            addPlaceholder()
        }
    }

    func startSession() {
        guard !isSessionRunning, !captureSession.inputs.isEmpty else { return }
        isSessionRunning = true
        DispatchQueue.global(qos: .userInitiated).async { [weak self] in
            self?.captureSession.startRunning()
        }
    }

    func stopSession() {
        guard isSessionRunning else { return }
        isSessionRunning = false
        DispatchQueue.global(qos: .userInitiated).async { [weak self] in
            self?.captureSession.stopRunning()
        }
    }

    // MARK: - Placeholders

    /// Generic placeholder (simulator / no camera hardware).
    private func addPlaceholder() {
        let iconConfig = UIImage.SymbolConfiguration(pointSize: 32, weight: .regular)
        let icon = UIImageView(image: UIImage(systemName: "camera.fill", withConfiguration: iconConfig))
        icon.tintColor = UIColor.white.withAlphaComponent(0.5)
        icon.translatesAutoresizingMaskIntoConstraints = false
        addSubview(icon)
        NSLayoutConstraint.activate([
            icon.centerXAnchor.constraint(equalTo: centerXAnchor),
            icon.centerYAnchor.constraint(equalTo: centerYAnchor),
        ])
    }

    /// Placeholder shown when camera access is denied — includes "Tap to enable" hint.
    private func addDeniedPlaceholder() {
        let stack = UIStackView()
        stack.axis = .vertical
        stack.alignment = .center
        stack.spacing = 4
        stack.translatesAutoresizingMaskIntoConstraints = false

        let iconConfig = UIImage.SymbolConfiguration(pointSize: 24, weight: .regular)
        let icon = UIImageView(image: UIImage(systemName: "camera.fill", withConfiguration: iconConfig))
        icon.tintColor = UIColor.white.withAlphaComponent(0.4)

        let label = UILabel()
        label.text = "Enable Camera"
        label.font = .systemFont(ofSize: 10, weight: .medium)
        label.textColor = UIColor.white.withAlphaComponent(0.4)

        stack.addArrangedSubview(icon)
        stack.addArrangedSubview(label)
        addSubview(stack)
        NSLayoutConstraint.activate([
            stack.centerXAnchor.constraint(equalTo: centerXAnchor),
            stack.centerYAnchor.constraint(equalTo: centerYAnchor),
        ])

        // Tap opens Settings
        let tap = UITapGestureRecognizer(target: self, action: #selector(openSettings))
        addGestureRecognizer(tap)
    }

    @objc private func openSettings() {
        guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
        UIApplication.shared.open(url)
    }
}
