import SwiftUI
import UniformTypeIdentifiers

/// The kinds of auxiliary panel that can sit around the chat. Adding a new panel
/// type is a matter of adding a case here and a branch in `PanelHost`.
enum PanelKind: String, Codable, CaseIterable, Identifiable, Hashable, Sendable {
    case fileExplorer
    case editor
    case terminal

    var id: String { rawValue }

    var title: String {
        switch self {
        case .fileExplorer: "Files"
        case .editor: "Editor"
        case .terminal: "Terminal"
        }
    }

    var systemImage: String {
        switch self {
        case .fileExplorer: "folder"
        case .editor: "square.and.pencil"
        case .terminal: "terminal"
        }
    }
}

/// Where a panel lives relative to the always-centered chat. Chat is never a panel;
/// it has no slot.
enum PanelSlot: String, Codable, CaseIterable, Hashable, Sendable {
    case left, right, bottom

    var label: String {
        switch self {
        case .left: "Left column"
        case .right: "Right column"
        case .bottom: "Bottom row"
        }
    }

    var systemImage: String {
        switch self {
        case .left: "sidebar.left"
        case .right: "sidebar.right"
        case .bottom: "rectangle.bottomhalf.inset.filled"
        }
    }
}

/// A concrete placed panel. The `id` lets the same `kind` appear in more than one
/// slot and lets a drag identify *which* panel is being moved.
struct PanelInstance: Codable, Identifiable, Equatable, Hashable, Sendable {
    var id: UUID
    var kind: PanelKind

    init(id: UUID = UUID(), kind: PanelKind) {
        self.id = id
        self.kind = kind
    }
}

/// A full arrangement of panels around the chat, plus the sizes of the three
/// regions. Used both as the live working arrangement and as a saved, named layout.
struct PanelLayout: Codable, Identifiable, Equatable, Sendable {
    var id: UUID
    var name: String
    var left: [PanelInstance]
    var right: [PanelInstance]
    var bottom: [PanelInstance]
    var leftWidth: CGFloat
    var rightWidth: CGFloat
    var bottomHeight: CGFloat

    init(
        id: UUID = UUID(), name: String = "Working",
        left: [PanelInstance] = [], right: [PanelInstance] = [], bottom: [PanelInstance] = [],
        leftWidth: CGFloat = 280, rightWidth: CGFloat = 280, bottomHeight: CGFloat = 240
    ) {
        self.id = id
        self.name = name
        self.left = left
        self.right = right
        self.bottom = bottom
        self.leftWidth = leftWidth
        self.rightWidth = rightWidth
        self.bottomHeight = bottomHeight
    }

    /// An empty arrangement — just the chat, no panels.
    static let empty = PanelLayout(name: "Just chat")

    func instances(in slot: PanelSlot) -> [PanelInstance] {
        switch slot {
        case .left: left
        case .right: right
        case .bottom: bottom
        }
    }

    /// The same layout, but anonymized into a fresh working copy (new ids) so saved
    /// layouts and the live working arrangement never alias each other's `id`.
    func asWorkingCopy() -> PanelLayout {
        PanelLayout(
            name: "Working",
            left: left, right: right, bottom: bottom,
            leftWidth: leftWidth, rightWidth: rightWidth, bottomHeight: bottomHeight)
    }
}

/// The payload carried by a panel drag. A drag from the palette creates a new panel
/// (`instanceID == nil`); a drag from an existing panel's header moves it
/// (`instanceID` set), so the drop can remove it from its old slot.
struct PanelDrag: Codable, Transferable, Sendable {
    var instanceID: UUID?
    var kind: PanelKind

    static var transferRepresentation: some TransferRepresentation {
        CodableRepresentation(contentType: .nucleicPanel)
    }
}

extension UTType {
    /// In-app drag type for panels. Declared dynamically — these drags never leave
    /// the app, so no Info.plist export is required.
    static let nucleicPanel = UTType(exportedAs: "com.nucleic.panel")
}
