import Foundation
import NucleicProtocol

/// Which side of a transfer this Mac is on (mesh P5).
public enum TransferDirection: String, Sendable, Codable {
    /// This Mac is the source — packaging and sending a session away.
    case outbound
    /// This Mac is the destination — receiving and staging a session.
    case inbound
}

/// The durable state of an in-flight transfer, persisted in `session_transfer` so a relaunch
/// can reconcile deterministically and so `WorktreeManager`/sweeps never touch a session that
/// is mid-transfer. States are per-direction; the terminal states clear the lock.
public enum SessionTransferState: String, Sendable, Codable {
    // Outbound (source):
    /// Offer sent, awaiting accept/reject.
    case offering
    /// Streaming chunks to the destination.
    case streaming
    /// All chunks sent, awaiting `transferReady`.
    case awaitingReady
    /// Destination staged the session and we durably tombstoned the source — the commit point.
    /// A relaunch finding this re-sends `transferCommit` (idempotent) rather than reviving the session.
    case tombstoned
    /// Destination acked the commit — terminal for the source (worktree then discarded).
    case committed

    // Inbound (destination):
    /// Receiving + verifying chunks; the session is staged non-runnable.
    case staging
    /// Every item verified and staged; `transferReady` sent, awaiting `transferCommit`.
    case ready
    /// Committed — the session is live here. Terminal for the destination.
    case activated

    /// Whether the transfer is still in flight (the session must not be swept/pruned/run).
    public var isActive: Bool {
        switch self {
        case .committed, .activated: false
        default: true
        }
    }
}

/// One row of the `session_transfer` table — the persisted transfer lock (mesh P5).
public struct SessionTransferLock: Sendable, Equatable {
    public let transferID: String
    public let sessionID: SessionID
    public let direction: TransferDirection
    /// The peer's `HostID` — the destination for an outbound transfer, the source for inbound.
    public let peerDeviceID: String
    public var state: SessionTransferState
    public let createdAt: Date
    public var updatedAt: Date

    public init(
        transferID: String, sessionID: SessionID, direction: TransferDirection,
        peerDeviceID: String, state: SessionTransferState, createdAt: Date, updatedAt: Date
    ) {
        self.transferID = transferID
        self.sessionID = sessionID
        self.direction = direction
        self.peerDeviceID = peerDeviceID
        self.state = state
        self.createdAt = createdAt
        self.updatedAt = updatedAt
    }
}

/// Thrown when a session already has an active transfer (the UNIQUE-while-active guard).
public struct SessionTransferConflict: Error, Sendable, Equatable {
    public let sessionID: SessionID
    public init(sessionID: SessionID) { self.sessionID = sessionID }
}
