import Foundation

public struct Workspace: Identifiable, Hashable, Codable, Sendable {
    public var id: UUID
    public var name: String
    public var rootURL: URL
    public var items: [WorkspaceItem]

    public init(
        id: UUID = UUID(),
        name: String,
        rootURL: URL,
        items: [WorkspaceItem] = []
    ) {
        self.id = id
        self.name = name
        self.rootURL = rootURL
        self.items = items
    }
}

public indirect enum WorkspaceItem: Identifiable, Hashable, Codable, Sendable {
    case folder(WorkspaceFolder)
    case file(WorkspaceFile)
    case project(Project)
    case subproject(Subproject)

    public var id: UUID {
        switch self {
        case .folder(let folder): folder.id
        case .file(let file): file.id
        case .project(let project): project.id
        case .subproject(let subproject): subproject.id
        }
    }

    public var displayName: String {
        switch self {
        case .folder(let folder): folder.name
        case .file(let file): file.name
        case .project(let project): project.name
        case .subproject(let subproject): subproject.name
        }
    }
}

public struct WorkspaceFolder: Identifiable, Hashable, Codable, Sendable {
    public var id: UUID
    public var name: String
    public var url: URL
    public var children: [WorkspaceItem]

    public init(
        id: UUID = UUID(),
        name: String,
        url: URL,
        children: [WorkspaceItem] = []
    ) {
        self.id = id
        self.name = name
        self.url = url
        self.children = children
    }
}

public struct WorkspaceFile: Identifiable, Hashable, Codable, Sendable {
    public var id: UUID
    public var name: String
    public var url: URL
    public var kind: WorkspaceFileKind

    public init(
        id: UUID = UUID(),
        name: String,
        url: URL,
        kind: WorkspaceFileKind
    ) {
        self.id = id
        self.name = name
        self.url = url
        self.kind = kind
    }
}

public enum WorkspaceFileKind: String, Hashable, Codable, Sendable {
    case markdown
    case attachment
    case other
}

public struct Project: Identifiable, Hashable, Codable, Sendable {
    public var id: UUID
    public var name: String
    public var repositoryURL: URL
    public var gitRepository: GitRepository
    public var remotes: [GitRemote]
    public var branches: [GitBranch]
    public var subprojects: [Subproject]
    public var usesGitLFS: Bool

    public init(
        id: UUID = UUID(),
        name: String,
        repositoryURL: URL,
        gitRepository: GitRepository,
        remotes: [GitRemote] = [],
        branches: [GitBranch] = [],
        subprojects: [Subproject] = [],
        usesGitLFS: Bool = false
    ) {
        self.id = id
        self.name = name
        self.repositoryURL = repositoryURL
        self.gitRepository = gitRepository
        self.remotes = remotes
        self.branches = branches
        self.subprojects = subprojects
        self.usesGitLFS = usesGitLFS
    }
}

public struct Subproject: Identifiable, Hashable, Codable, Sendable {
    public var id: UUID
    public var name: String
    public var path: String
    public var repositoryURL: URL
    public var remoteURL: URL?

    public init(
        id: UUID = UUID(),
        name: String,
        path: String,
        repositoryURL: URL,
        remoteURL: URL? = nil
    ) {
        self.id = id
        self.name = name
        self.path = path
        self.repositoryURL = repositoryURL
        self.remoteURL = remoteURL
    }
}

public struct MarkdownDocument: Identifiable, Hashable, Codable, Sendable {
    public var id: UUID
    public var url: URL
    public var title: String
    public var content: String
    public var attachments: [Attachment]

    public init(
        id: UUID = UUID(),
        url: URL,
        title: String,
        content: String,
        attachments: [Attachment] = []
    ) {
        self.id = id
        self.url = url
        self.title = title
        self.content = content
        self.attachments = attachments
    }
}

public struct Attachment: Identifiable, Hashable, Codable, Sendable {
    public var id: UUID
    public var filename: String
    public var url: URL
    public var kind: AttachmentKind
    public var isGitLFSManaged: Bool

    public init(
        id: UUID = UUID(),
        filename: String,
        url: URL,
        kind: AttachmentKind,
        isGitLFSManaged: Bool = false
    ) {
        self.id = id
        self.filename = filename
        self.url = url
        self.kind = kind
        self.isGitLFSManaged = isGitLFSManaged
    }
}

public enum AttachmentKind: String, Hashable, Codable, Sendable {
    case image
    case pdf
    case audio
    case video
    case binary
}

public struct GitRepository: Identifiable, Hashable, Codable, Sendable {
    public var id: UUID
    public var name: String
    public var rootURL: URL
    public var currentBranch: GitBranch?
    public var remotes: [GitRemote]
    public var statusSummary: GitStatusSummary

    public init(
        id: UUID = UUID(),
        name: String,
        rootURL: URL,
        currentBranch: GitBranch? = nil,
        remotes: [GitRemote] = [],
        statusSummary: GitStatusSummary = .clean
    ) {
        self.id = id
        self.name = name
        self.rootURL = rootURL
        self.currentBranch = currentBranch
        self.remotes = remotes
        self.statusSummary = statusSummary
    }
}

public struct GitRemote: Identifiable, Hashable, Codable, Sendable {
    public var id: UUID
    public var name: String
    public var url: URL
    public var fetchURL: URL?
    public var pushURL: URL?

    public init(
        id: UUID = UUID(),
        name: String,
        url: URL,
        fetchURL: URL? = nil,
        pushURL: URL? = nil
    ) {
        self.id = id
        self.name = name
        self.url = url
        self.fetchURL = fetchURL
        self.pushURL = pushURL
    }
}

public struct GitBranch: Identifiable, Hashable, Codable, Sendable {
    public var id: UUID
    public var name: String
    public var isCurrent: Bool
    public var upstreamName: String?

    public init(
        id: UUID = UUID(),
        name: String,
        isCurrent: Bool = false,
        upstreamName: String? = nil
    ) {
        self.id = id
        self.name = name
        self.isCurrent = isCurrent
        self.upstreamName = upstreamName
    }
}

public struct GitCommit: Identifiable, Hashable, Codable, Sendable {
    public var id: String
    public var shortHash: String
    public var authorName: String
    public var authorEmail: String
    public var message: String
    public var authoredAt: Date

    public init(
        id: String,
        shortHash: String,
        authorName: String,
        authorEmail: String,
        message: String,
        authoredAt: Date
    ) {
        self.id = id
        self.shortHash = shortHash
        self.authorName = authorName
        self.authorEmail = authorEmail
        self.message = message
        self.authoredAt = authoredAt
    }
}

public struct GitFileStatus: Identifiable, Hashable, Codable, Sendable {
    public var id: UUID
    public var path: String
    public var state: GitFileState

    public init(id: UUID = UUID(), path: String, state: GitFileState) {
        self.id = id
        self.path = path
        self.state = state
    }
}

public enum GitFileState: String, Hashable, Codable, Sendable {
    case untracked
    case added
    case modified
    case deleted
    case renamed
    case conflicted
}

public enum GitStatusSummary: String, Hashable, Codable, Sendable {
    case clean
    case dirty
    case conflicted
    case unknown
}
