/**
 * Stale Good-First-Issue Watcher Service
 *
 * Periodically polls every connected repository (with a `remoteUrl`)
 * and dispatches `DetectStaleGoodFirstIssueUseCase`. The use case is
 * pure — it returns the structured stale list — and the watcher's only
 * job is to feed it the right `(owner, repo)` tuples and surface
 * results via the desktop notifier so a maintainer notices.
 *
 * Time-driven side of spec 097, FR-42 (research decision 9). The split
 * with GitHub Actions is deliberate: webhook-driven workflows (welcome,
 * label-by-lane) live in `.github/workflows/`; cadence-driven workloads
 * run inside the Shep daemon so adopting projects without an always-on
 * Shep instance still get the inbound automation.
 */
export const DEFAULT_STALE_POLL_INTERVAL_MS = 24 * 60 * 60 * 1000;
const DEFAULT_STALE_DAYS = 30;
export class StaleGoodFirstIssueWatcherService {
    useCase;
    repositoryRepo;
    githubService;
    notifier;
    pollIntervalMs;
    staleDays;
    intervalId = null;
    constructor(useCase, repositoryRepo, githubService, notifier, pollIntervalMs = DEFAULT_STALE_POLL_INTERVAL_MS, staleDays = DEFAULT_STALE_DAYS) {
        this.useCase = useCase;
        this.repositoryRepo = repositoryRepo;
        this.githubService = githubService;
        this.notifier = notifier;
        this.pollIntervalMs = pollIntervalMs;
        this.staleDays = staleDays;
    }
    isRunning() {
        return this.intervalId !== null;
    }
    start() {
        if (this.intervalId !== null)
            return;
        void this.poll();
        this.intervalId = setInterval(() => {
            void this.poll();
        }, this.pollIntervalMs);
    }
    stop() {
        if (this.intervalId !== null) {
            clearInterval(this.intervalId);
            this.intervalId = null;
        }
    }
    async poll() {
        let repositories;
        try {
            repositories = await this.repositoryRepo.list();
        }
        catch {
            return;
        }
        for (const repo of repositories) {
            if (!repo.remoteUrl)
                continue;
            let parsed;
            try {
                parsed = this.githubService.parseGitHubUrl(repo.remoteUrl);
            }
            catch {
                continue;
            }
            try {
                const result = await this.useCase.execute({
                    owner: parsed.owner,
                    repo: parsed.repo,
                    staleDays: this.staleDays,
                });
                if (result.stale.length > 0) {
                    this.notifier.send('Stale good-first-issues detected', `${result.stale.length} good-first-issue(s) in ${parsed.owner}/${parsed.repo} are over ${result.thresholdDays} days old.`);
                }
            }
            catch {
                // Per-repo failures are isolated; continue with other repos.
            }
        }
    }
}
let watcherInstance = null;
export function initializeStaleGoodFirstIssueWatcher(useCase, repositoryRepo, githubService, notifier, pollIntervalMs, staleDays) {
    if (watcherInstance !== null) {
        throw new Error('Stale good-first-issue watcher already initialized. Cannot re-initialize.');
    }
    watcherInstance = new StaleGoodFirstIssueWatcherService(useCase, repositoryRepo, githubService, notifier, pollIntervalMs, staleDays);
}
export function getStaleGoodFirstIssueWatcher() {
    if (watcherInstance === null) {
        throw new Error('Stale good-first-issue watcher not initialized. Call initializeStaleGoodFirstIssueWatcher() during web server startup.');
    }
    return watcherInstance;
}
export function hasStaleGoodFirstIssueWatcher() {
    return watcherInstance !== null;
}
export function resetStaleGoodFirstIssueWatcher() {
    if (watcherInstance !== null) {
        watcherInstance.stop();
    }
    watcherInstance = null;
}
