import ActiveApplicationMonitor
import AppKit
import AXExtension
import BuiltinExtension
import Foundation
import Logger
import Workspace
import XcodeInspector

public final class ScheduledCleaner {
    weak var service: Service?

    init() {}

    func start() {
        Task { @ServiceActor in
            while !Task.isCancelled {
                try await Task.sleep(nanoseconds: 10 * 60 * 1_000_000_000)
                await cleanUp()
            }
        }

        Task { @ServiceActor in
            for await app in ActiveApplicationMonitor.shared.createInfoStream() {
                try Task.checkCancellation()
                if let app, !app.isXcode {
                    await cleanUp()
                }
            }
        }
    }

    @ServiceActor
    func cleanUp() async {
        guard let service else { return }

        let workspaceInfos = XcodeInspector.shared.xcodes.reduce(
            into: [
                XcodeAppInstanceInspector.WorkspaceIdentifier:
                    XcodeAppInstanceInspector.WorkspaceInfo
            ]()
        ) { result, xcode in
            let infos = xcode.realtimeWorkspaces
            for (id, info) in infos {
                if let existed = result[id] {
                    result[id] = existed.combined(with: info)
                } else {
                    result[id] = info
                }
            }
        }
        for (url, workspace) in service.workspacePool.workspaces {
            if workspace.isExpired, workspaceInfos[.url(url)] == nil {
                Logger.service.info("Remove idle workspace")
                _ = await Task { @MainActor in
                    service.guiController.store.send(
                        .promptToCodeGroup(.discardExpiredPromptToCode(documentURLs: Array(
                            workspace.filespaces.keys
                        )))
                    )
                }.result
                await workspace.cleanUp(availableTabs: [])
                await service.workspacePool.removeWorkspace(url: url)
            } else {
                let tabs = (workspaceInfos[.url(url)]?.tabs ?? [])
                    .union(workspaceInfos[.unknown]?.tabs ?? [])
                // cleanup chats for unused files
                let filespaces = workspace.filespaces
                for (url, _) in filespaces {
                    if workspace.isFilespaceExpired(
                        fileURL: url,
                        availableTabs: tabs
                    ) {
                        _ = await Task { @MainActor in
                            service.guiController.store.send(
                                .promptToCodeGroup(.discardExpiredPromptToCode(documentURLs: [url]))
                            )
                        }.result
                    }
                }
                // cleanup workspace
                await workspace.cleanUp(availableTabs: tabs)
            }
        }
    }

    @ServiceActor
    public func closeAllChildProcesses() async {
        BuiltinExtensionManager.shared.terminate()
    }
}

