import SwiftUI

// MARK: - Dark Mode Animation System
// Ported from DarkModeAnimation reference project (Balaji Venkatesh).
// Circular reveal mask animation for theme switching.

// Step 1: Wrap app's main content with DarkModeWrapper in RosettaApp.
// Step 2: Place DarkModeButton wherever the toggle should appear.

/// Creates an overlay UIWindow for the dark mode transition animation.
/// Supports three theme modes: dark, light, system (via `rosetta_theme_mode`).
struct DarkModeWrapper<Content: View>: View {
    @ViewBuilder var content: Content
    @State private var overlayWindow: UIWindow?
    @AppStorage("rosetta_theme_mode") private var themeModeRaw: String = "dark"

    var body: some View {
        content
            .onAppear {
                // Migrate legacy `rosetta_dark_mode` Bool → `rosetta_theme_mode` String
                let defaults = UserDefaults.standard
                if defaults.object(forKey: "rosetta_theme_mode") == nil,
                   let legacy = defaults.object(forKey: "rosetta_dark_mode") as? Bool {
                    themeModeRaw = legacy ? "dark" : "light"
                    defaults.removeObject(forKey: "rosetta_dark_mode")
                }
                if overlayWindow == nil {
                    if let windowScene = activeWindowScene {
                        let overlayWindow = UIWindow(windowScene: windowScene)
                        overlayWindow.tag = 0320
                        overlayWindow.isHidden = false
                        overlayWindow.isUserInteractionEnabled = false
                        self.overlayWindow = overlayWindow
                    }
                }
            }
            .onChange(of: themeModeRaw, initial: true) { _, newValue in
                if let windowScene = activeWindowScene {
                    let style: UIUserInterfaceStyle
                    switch newValue {
                    case "light": style = .light
                    case "system": style = .unspecified
                    default: style = .dark
                    }
                    for window in windowScene.windows {
                        window.overrideUserInterfaceStyle = style
                    }
                }
            }
    }

    private var activeWindowScene: UIWindowScene? {
        let scenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }
        return scenes.first(where: { $0.activationState == .foregroundActive }) ?? scenes.first
    }
}

/// Theme toggle button with sun/moon icon and circular reveal animation.
/// Cycles: dark → light → dark (quick toggle, full control in Appearance settings).
struct DarkModeButton: View {
    @State private var buttonRect: CGRect = .zero
    /// Local icon state — changes INSTANTLY on tap (no round-trip through UserDefaults).
    @State private var showMoonIcon: Bool = true
    @AppStorage("rosetta_theme_mode") private var themeModeRaw: String = "dark"

    var body: some View {
        Button(action: {
            showMoonIcon.toggle()
            animateScheme()
        }, label: {
            Image(systemName: showMoonIcon ? "moon.fill" : "sun.max.fill")
                .font(.system(size: 16, weight: .medium))
                .foregroundStyle(RosettaColors.Adaptive.text)
                .symbolEffect(.bounce, value: showMoonIcon)
                .frame(width: 44, height: 44)
        })
        .buttonStyle(.plain)
        .onAppear { showMoonIcon = themeModeRaw == "dark" || themeModeRaw == "system" }
        .darkModeButtonRect { rect in
            buttonRect = rect
        }
    }

    @MainActor
    func animateScheme() {
        guard let windowScene = activeWindowScene,
              let window = windowScene.windows.first(where: { $0.isKeyWindow }),
              let overlayWindow = windowScene.windows.first(where: { $0.tag == 0320 })
        else { return }

        let targetDark = showMoonIcon
        let frameSize = window.frame.size

        // 1. Capture old state SYNCHRONOUSLY — afterScreenUpdates:false is fast (~5ms).
        let previousImage = window.darkModeSnapshotFast(frameSize)

        // 2. Show freeze frame IMMEDIATELY — user sees instant response.
        // Overlay stays non-interactive so button taps always pass through.
        let imageView = UIImageView(image: previousImage)
        imageView.frame = window.frame
        imageView.contentMode = .scaleAspectFit
        overlayWindow.addSubview(imageView)

        // 3. Switch theme underneath the freeze frame (invisible to user).
        themeModeRaw = targetDark ? "dark" : "light"

        // 4. Capture new state asynchronously after layout settles.
        Task {
            try? await Task.sleep(for: .seconds(0.06))
            window.layoutIfNeeded()
            let currentImage = window.darkModeSnapshot(frameSize)

            let swiftUIView = DarkModeOverlayView(
                buttonRect: buttonRect,
                previousImage: previousImage,
                currentImage: currentImage
            )

            let hostingController = UIHostingController(rootView: swiftUIView)
            hostingController.view.backgroundColor = .clear
            hostingController.view.frame = window.frame
            hostingController.view.tag = 1009
            overlayWindow.addSubview(hostingController.view)
            imageView.removeFromSuperview()
        }
    }

    private var activeWindowScene: UIWindowScene? {
        let scenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }
        return scenes.first(where: { $0.activationState == .foregroundActive }) ?? scenes.first
    }
}

// MARK: - Button Rect Tracking

private struct DarkModeRectKey: PreferenceKey {
    static var defaultValue: CGRect = .zero
    static func reduce(value: inout CGRect, nextValue: () -> CGRect) {
        value = nextValue()
    }
}

private extension View {
    @ViewBuilder
    func darkModeButtonRect(value: @escaping (CGRect) -> Void) -> some View {
        self
            .overlay {
                GeometryReader { geometry in
                    let rect = geometry.frame(in: .global)
                    Color.clear
                        .preference(key: DarkModeRectKey.self, value: rect)
                        .onPreferenceChange(DarkModeRectKey.self) { rect in
                            value(rect)
                        }
                }
            }
    }
}

// MARK: - Circular Mask Animation Overlay

private struct DarkModeOverlayView: View {
    var buttonRect: CGRect
    @State var previousImage: UIImage?
    @State var currentImage: UIImage?
    @State private var maskAnimation: Bool = false

    var body: some View {
        GeometryReader { geometry in
            let size = geometry.size
            let maskRadius = size.height / 10

            if let previousImage, let currentImage {
                ZStack {
                    Image(uiImage: previousImage)
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: size.width, height: size.height)

                    Image(uiImage: currentImage)
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: size.width, height: size.height)
                        .mask(alignment: .topLeading) {
                            Circle()
                                .frame(
                                    width: buttonRect.width * (maskAnimation ? maskRadius : 1),
                                    height: buttonRect.height * (maskAnimation ? maskRadius : 1),
                                    alignment: .bottomLeading
                                )
                                .frame(width: buttonRect.width, height: buttonRect.height)
                                .offset(x: buttonRect.minX, y: buttonRect.minY)
                                .ignoresSafeArea()
                        }
                }
                .task {
                    guard !maskAnimation else { return }

                    withAnimation(.easeInOut(duration: 0.9), completionCriteria: .logicallyComplete) {
                        maskAnimation = true
                    } completion: {
                        self.previousImage = nil
                        self.currentImage = nil
                        maskAnimation = false
                        if let window = (UIApplication.shared.connectedScenes.first as? UIWindowScene)?.windows.first(where: { $0.tag == 0320 }) {
                            for view in window.subviews {
                                view.removeFromSuperview()
                            }
                        }
                    }
                }
            }
        }
        // Reverse masking — cut out the button area so original button stays visible
        .mask {
            Rectangle()
                .overlay(alignment: .topLeading) {
                    Circle()
                        .frame(width: buttonRect.width, height: buttonRect.height)
                        .offset(x: buttonRect.minX, y: buttonRect.minY)
                        .blendMode(.destinationOut)
                }
        }
        .ignoresSafeArea()
    }
}

// MARK: - UIView Snapshot

private extension UIView {
    /// Full-fidelity snapshot — waits for pending layout. Use for the NEW state.
    func darkModeSnapshot(_ size: CGSize) -> UIImage {
        let renderer = UIGraphicsImageRenderer(size: size)
        return renderer.image { _ in
            drawHierarchy(in: .init(origin: .zero, size: size), afterScreenUpdates: true)
        }
    }

    /// Fast snapshot of CURRENT appearance — no layout wait (~5ms vs ~80ms).
    /// Use for the OLD state (already on screen, nothing pending).
    func darkModeSnapshotFast(_ size: CGSize) -> UIImage {
        let renderer = UIGraphicsImageRenderer(size: size)
        return renderer.image { _ in
            drawHierarchy(in: .init(origin: .zero, size: size), afterScreenUpdates: false)
        }
    }
}
