import SwiftUI
import SwiftTerm

/// Main view rendered inside each NotchWindow.
///
/// Opacity strategy: EVERY element has a solid black background.
/// A single `.opacity(notchOpacity)` is applied at the outermost
/// level so everything becomes uniformly transparent — no double
/// layering, no mismatched areas.
struct ContentView: View {

    @ObservedObject var screen: ScreenContext
    let orchestrator: NotchOrchestrator
    @ObservedObject private var settingsController = AppSettingsController.shared
    @ObservedObject private var screenRegistry = ScreenRegistry.shared

    @State private var resizeStartSize: CGSize?
    @State private var resizeStartMouseLocation: CGPoint?

    private var hoverAnimation: Animation {
        .interactiveSpring(response: hoverSpringResponse, dampingFraction: hoverSpringDamping)
    }

    private var currentShape: NotchShape {
        screen.notchState == .open
            ? (cornerRadiusScaling ? .opened : NotchShape(topCornerRadius: 0, bottomCornerRadius: 14))
            : .closed
    }

    private var enableShadow: Bool {
        settingsController.settings.appearance.enableShadow
    }

    private var shadowRadius: Double {
        settingsController.settings.appearance.shadowRadius
    }

    private var shadowOpacity: Double {
        settingsController.settings.appearance.shadowOpacity
    }

    private var cornerRadiusScaling: Bool {
        settingsController.settings.appearance.cornerRadiusScaling
    }

    private var notchOpacity: Double {
        settingsController.settings.appearance.notchOpacity
    }

    private var blurRadius: Double {
        settingsController.settings.appearance.blurRadius
    }

    private var hoverSpringResponse: Double {
        settingsController.settings.animation.hoverSpringResponse
    }

    private var hoverSpringDamping: Double {
        settingsController.settings.animation.hoverSpringDamping
    }

    // MARK: - Body

    var body: some View {
        notchBody
            .accessibilityIdentifier("notch.container")
            .frame(
                width: screen.notchSize.width,
                height: screen.notchState == .open ? screen.notchSize.height : screen.closedNotchSize.height,
                alignment: .top
            )
            .background(.black)
            .clipShape(currentShape)
            .overlay(alignment: .top) {
                Rectangle().fill(.black).frame(height: 1)
            }
            .overlay(alignment: .bottomTrailing) {
                if screen.notchState == .open {
                    resizeHandle
                }
            }
            .shadow(
                color: enableShadow ? Color.black.opacity(shadowOpacity) : .clear,
                radius: enableShadow ? shadowRadius : 0
            )
            // Single opacity control — everything inside is solid black,
            // so this one modifier makes it all uniformly transparent.
            .opacity(notchOpacity)
            .blur(radius: blurRadius)
            .animation(screen.notchState == .open ? screen.openAnimation : screen.closeAnimation, value: screen.notchState)
            .animation(sizeAnimation, value: screen.notchSize.width)
            .animation(sizeAnimation, value: screen.notchSize.height)
            .onHover { handleHover($0) }
            .onDisappear {
                resizeStartSize = nil
                resizeStartMouseLocation = nil
                screen.endInteractiveResize()
                orchestrator.handleHoverChange(false, for: screen.id)
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
            .edgesIgnoringSafeArea(.all)
    }

    // MARK: - Content

    @ViewBuilder
    private var notchBody: some View {
        WorkspaceScopedView(screen: screen, screenRegistry: screenRegistry) { workspace in
            if screen.notchState == .open {
                openContent(workspace: workspace)
                    .transition(.opacity)
            } else {
                closedContent(workspace: workspace)
            }
        }
    }

    private func closedContent(workspace: WorkspaceController) -> some View {
        HStack {
            Spacer()
            Text(abbreviate(workspace.activeTitle))
                .font(.system(size: 10, weight: .medium))
                .foregroundStyle(.white.opacity(0.7))
                .lineLimit(1)
            Spacer()
        }
        .padding(.horizontal, 8)
        .background(.black)
    }

    private var resizeHandle: some View {
        ResizeHandleShape()
            .stroke(.white.opacity(0.32), style: StrokeStyle(lineWidth: 1.2, lineCap: .round))
            .frame(width: 16, height: 16)
            .padding(.trailing, 8)
            .padding(.bottom, 8)
            .contentShape(Rectangle().inset(by: -8))
            .gesture(resizeGesture)
    }

    private var resizeGesture: some Gesture {
        DragGesture(minimumDistance: 0)
            .onChanged { value in
                if resizeStartSize == nil {
                    resizeStartSize = screen.notchSize
                    resizeStartMouseLocation = NSEvent.mouseLocation
                    screen.beginInteractiveResize()
                }

                guard let startSize = resizeStartSize,
                      let startMouseLocation = resizeStartMouseLocation else { return }
                let currentMouseLocation = NSEvent.mouseLocation
                screen.resizeOpenNotch(
                    to: CGSize(
                        width: startSize.width + ((currentMouseLocation.x - startMouseLocation.x) * 2),
                        height: startSize.height + (startMouseLocation.y - currentMouseLocation.y)
                    )
                )
            }
            .onEnded { _ in
                resizeStartSize = nil
                resizeStartMouseLocation = nil
                screen.endInteractiveResize()
            }
    }

    private var sizeAnimation: Animation? {
        guard !screen.isUserResizing, !screen.isPresetResizing else { return nil }
        return screen.notchState == .open ? screen.openAnimation : screen.closeAnimation
    }

    /// Open layout: VStack with toolbar row on top, terminal in the middle,
    /// tab bar at the bottom. Every section has a black background.
    private func openContent(workspace: WorkspaceController) -> some View {
        VStack(spacing: 0) {
            // Toolbar row — right-aligned, solid black
            HStack {
                WorkspaceSwitcherView(screen: screen, orchestrator: orchestrator)
                Spacer()
                toolbarButton(icon: "arrow.up.forward.square", help: "Detach tab") {
                    if let session = workspace.detachActiveTab() {
                        PopoutWindowController.shared.popout(session: session)
                    }
                }
                toolbarButton(icon: "gearshape.fill", help: "Settings") {
                    SettingsWindowController.shared.showSettings()
                }
            }
            .padding(.top, 6)
            .padding(.leading, 10)
            .padding(.trailing, 10)
            .padding(.bottom, 2)
            .background(.black)

            // Terminal — fills remaining space
            if let session = workspace.activeTab {
                SwiftTermView(session: session)
                    .id(session.id)
                    .padding(.leading, 10)
                    .padding(.trailing, 10)
            }

            // Tab bar
            TabBar(workspace: workspace)
        }
        .background(.black)
    }

    private func toolbarButton(icon: String, help: String, action: @escaping () -> Void) -> some View {
        Button(action: action) {
            Image(systemName: icon)
                .font(.system(size: 11))
                .foregroundStyle(.white.opacity(0.45))
                .padding(4)
                .contentShape(Rectangle())
        }
        .buttonStyle(.plain)
        .accessibilityLabel(help)
        .accessibilityIdentifier("notch.toolbar.\(icon)")
        .help(help)
    }

    // MARK: - Hover

    private func handleHover(_ hovering: Bool) {
        withAnimation(hoverAnimation) {
            orchestrator.handleHoverChange(hovering, for: screen.id)
        }
    }

    private func abbreviate(_ title: String) -> String {
        title.count <= 30 ? title : String(title.prefix(28)) + "…"
    }
}

private struct ResizeHandleShape: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()
        path.move(to: CGPoint(x: rect.maxX - 10, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - 10))
        path.move(to: CGPoint(x: rect.maxX - 6, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - 6))
        path.move(to: CGPoint(x: rect.maxX - 2, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - 2))
        return path
    }
}

private struct WorkspaceScopedView<Content: View>: View {
    @ObservedObject var screen: ScreenContext
    @ObservedObject var screenRegistry: ScreenRegistry
    let content: (WorkspaceController) -> Content

    init(
        screen: ScreenContext,
        screenRegistry: ScreenRegistry,
        @ViewBuilder content: @escaping (WorkspaceController) -> Content
    ) {
        self.screen = screen
        self.screenRegistry = screenRegistry
        self.content = content
    }

    var body: some View {
        WorkspaceObservedView(workspace: screenRegistry.workspaceController(for: screen.id), content: content)
            .id(screen.workspaceID)
    }
}

private struct WorkspaceObservedView<Content: View>: View {
    @ObservedObject var workspace: WorkspaceController
    let content: (WorkspaceController) -> Content

    var body: some View {
        content(workspace)
    }
}
