import Foundation
import SaplingCore
import SaplingGit
import SaplingStorage

public protocol WorkspaceManaging: Sendable {
    func openWorkspace(at url: URL) async throws -> Workspace
    func sampleWorkspace() -> Workspace
}

public final class LocalWorkspaceManager: WorkspaceManaging, @unchecked Sendable {
    private let gitProvider: any GitProvider
    private let metadataStore: any WorkspaceMetadataStore
    private let fileManager: FileManager

    public init(
        gitProvider: any GitProvider,
        metadataStore: any WorkspaceMetadataStore,
        fileManager: FileManager = .default
    ) {
        self.gitProvider = gitProvider
        self.metadataStore = metadataStore
        self.fileManager = fileManager
    }

    public func openWorkspace(at url: URL) async throws -> Workspace {
        let items = try scanItems(at: url, relativeTo: url)
        let workspace = Workspace(name: url.lastPathComponent, rootURL: url, items: items)
        try SaplingRules.validateWorkspace(workspace)
        try metadataStore.saveMetadata(WorkspaceMetadata(workspaceID: workspace.id))
        return workspace
    }

    public func sampleWorkspace() -> Workspace {
        SaplingSampleData.workspace
    }

    private func scanItems(at url: URL, relativeTo rootURL: URL) throws -> [WorkspaceItem] {
        guard let children = try? fileManager.contentsOfDirectory(
            at: url,
            includingPropertiesForKeys: [.isDirectoryKey],
            options: [.skipsHiddenFiles]
        ) else {
            return []
        }

        return try children
            .sorted { $0.lastPathComponent.localizedStandardCompare($1.lastPathComponent) == .orderedAscending }
            .map { childURL in
                if isGitRepository(at: childURL) {
                    return .project(project(at: childURL))
                }

                let values = try childURL.resourceValues(forKeys: [.isDirectoryKey])
                if values.isDirectory == true {
                    return .folder(
                        WorkspaceFolder(
                            name: childURL.lastPathComponent,
                            url: childURL,
                            children: try scanItems(at: childURL, relativeTo: rootURL)
                        )
                    )
                }

                return .file(
                    WorkspaceFile(
                        name: childURL.lastPathComponent,
                        url: childURL,
                        kind: fileKind(for: childURL)
                    )
                )
            }
    }

    private func isGitRepository(at url: URL) -> Bool {
        fileManager.fileExists(atPath: url.appendingPathComponent(".git").path)
    }

    private func project(at url: URL) -> Project {
        let repository = GitRepository(
            name: url.lastPathComponent,
            rootURL: url,
            statusSummary: .unknown
        )
        return Project(
            name: url.lastPathComponent,
            repositoryURL: url,
            gitRepository: repository
        )
    }

    private func fileKind(for url: URL) -> WorkspaceFileKind {
        switch url.pathExtension.lowercased() {
        case "md", "markdown":
            return .markdown
        case "png", "jpg", "jpeg", "gif", "webp", "pdf", "mp3", "mp4":
            return .attachment
        default:
            return .other
        }
    }
}
