import SwiftUI
import NucleicCore

/// Renders the concrete content for a panel instance, keyed so each panel keeps its
/// own state (terminal process, file selection) across redraws.
struct PanelHost: View {
    let instance: PanelInstance
    let session: Session?

    var body: some View {
        content
            // Re-root (and, for the terminal, restart the shell) when the open chat
            // changes: a new session id forces SwiftUI to rebuild this subtree at the
            // new worktree, rather than reusing the previous chat's process/tree.
            .id(PanelIdentity(instance: instance.id, session: session?.id))
    }

    @ViewBuilder
    private var content: some View {
        switch instance.kind {
        case .fileExplorer:
            FileExplorerPanel(root: session?.worktreePath, instanceID: instance.id)
        case .editor:
            EditorPanel()
        case .terminal:
            TerminalPanel(workingDirectory: session?.worktreePath)
        }
    }

    private struct PanelIdentity: Hashable {
        let instance: UUID
        let session: SessionID?
    }
}

/// How a pane draws its title bar.
enum PanelHeaderStyle {
    /// A slim flat strip in the sidebar tone (editor, terminal).
    case compact
    /// A taller header that mirrors the chat's own header band — `.headline` title
    /// over a caption subtitle, on the chat background with a divider beneath — so
    /// the pane's content starts on the same line as the chat transcript.
    case prominent
}

/// A framed panel: a title bar (name, drag source, close button) over its content.
/// The whole title bar is the drag source, so a panel can be dragged to another
/// slot; the × removes it.
struct PanelContainer: View {
    let instance: PanelInstance
    let session: Session?
    var headerStyle: PanelHeaderStyle = .compact
    /// Secondary line under the title in the prominent header (mirrors the chat
    /// header's status line); keeps the header the same height as the chat's.
    var headerSubtitle: String? = nil
    /// Pane-specific controls placed in the prominent header, left of the close
    /// button (e.g. the editor's Save/Preview icons).
    var headerAccessory: AnyView = AnyView(EmptyView())
    let onClose: () -> Void

    var body: some View {
        VStack(spacing: 0) {
            switch headerStyle {
            case .compact: compactHeader
            case .prominent: prominentHeader
            }
            Divider()
            content
        }
    }

    private var content: some View {
        PanelHost(instance: instance, session: session)
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(AppTheme.background)
    }

    /// A flat title strip, flush to the pane edges (no rounded card), mirroring the
    /// app's real sidebar tone so the pane reads as window chrome around the chat.
    private var compactHeader: some View {
        HStack(spacing: 6) {
            Image(systemName: instance.kind.systemImage)
                .font(.caption).foregroundStyle(.secondary)
            Text(instance.kind.title)
                .font(.system(size: 11, weight: .semibold))
                .foregroundStyle(.secondary)
                .textCase(.uppercase)
            Spacer()
            closeButton.font(.system(size: 9, weight: .semibold))
        }
        .padding(.horizontal, 10).padding(.vertical, 6)
        .frame(maxWidth: .infinity)
        .background(AppTheme.sidebar)
        .asDragSource(instance: instance)
    }

    /// Matches `SessionDetailView`'s header: a headline title over a caption
    /// subtitle, padded 12 on the chat background — so the Files header lines up
    /// with the chat header and the tree starts at the transcript's top.
    private var prominentHeader: some View {
        HStack(alignment: .top) {
            VStack(alignment: .leading, spacing: 2) {
                Text(instance.kind.title).font(.headline)
                Text(headerSubtitle ?? " ")
                    .font(.caption).foregroundStyle(.secondary).lineLimit(1)
            }
            Spacer(minLength: 12)
            headerAccessory
            closeButton.font(.body)
        }
        .padding(12)
        .frame(maxWidth: .infinity)
        .background(AppTheme.background)
        .asDragSource(instance: instance)
    }

    private var closeButton: some View {
        Button(action: onClose) {
            Image(systemName: "xmark")
        }
        .buttonStyle(.plain).foregroundStyle(.secondary)
        .help("Remove panel")
    }
}

private extension View {
    /// Makes a header strip the drag source for moving its pane to another slot.
    func asDragSource(instance: PanelInstance) -> some View {
        self
            .contentShape(Rectangle())
            .draggable(PanelDrag(instanceID: instance.id, kind: instance.kind)) {
                Label(instance.kind.title, systemImage: instance.kind.systemImage)
                    .font(.caption).padding(6)
                    .background(AppTheme.surface, in: .rect(cornerRadius: 6))
            }
            .help("Drag to move this panel")
    }
}
