/**
 * Git Platform Integration
 *
 * Native integration with GitHub and GitLab:
 * - Repository management
 * - Pull/Merge request operations
 * - Issue tracking
 * - CI/CD status
 */
import { EventEmitter } from 'events';
import { execSync } from 'child_process';
import { logger } from '../utils/logger';
/**
 * Git Platform Integration
 */
export class GitPlatformIntegration extends EventEmitter {
    config;
    detectedPlatform = null;
    repoInfo = null;
    constructor(config) {
        super();
        this.config = {
            platform: config.platform || 'auto',
            token: config.token || process.env.GITHUB_TOKEN || process.env.GITLAB_TOKEN || '',
            baseUrl: config.baseUrl || '',
            defaultOwner: config.defaultOwner || '',
            defaultRepo: config.defaultRepo || '',
        };
    }
    /**
     * Initialize and detect platform
     */
    async init() {
        if (this.config.platform === 'auto') {
            this.detectedPlatform = await this.detectPlatform();
        }
        else {
            this.detectedPlatform = this.config.platform;
        }
        this.repoInfo = await this.detectRepoInfo();
        if (!this.config.baseUrl) {
            this.config.baseUrl = this.detectedPlatform === 'github'
                ? 'https://api.github.com'
                : 'https://gitlab.com/api/v4';
        }
        this.emit('initialized', {
            platform: this.detectedPlatform,
            repo: this.repoInfo,
        });
    }
    /**
     * Detect platform from git remote
     */
    async detectPlatform() {
        try {
            const remoteUrl = execSync('git remote get-url origin', { encoding: 'utf-8' }).trim();
            if (remoteUrl.includes('github.com') || remoteUrl.includes('github.')) {
                return 'github';
            }
            else if (remoteUrl.includes('gitlab.com') || remoteUrl.includes('gitlab.')) {
                return 'gitlab';
            }
        }
        catch {
            // Not a git repository
        }
        return null;
    }
    /**
     * Detect repository info from git remote
     */
    async detectRepoInfo() {
        try {
            const remoteUrl = execSync('git remote get-url origin', { encoding: 'utf-8' }).trim();
            // Parse SSH URL: git@github.com:owner/repo.git
            const sshMatch = remoteUrl.match(/@[^:]+:([^/]+)\/([^.]+)/);
            if (sshMatch) {
                return { owner: sshMatch[1], repo: sshMatch[2] };
            }
            // Parse HTTPS URL: https://github.com/owner/repo.git
            const httpsMatch = remoteUrl.match(/\/\/[^/]+\/([^/]+)\/([^.]+)/);
            if (httpsMatch) {
                return { owner: httpsMatch[1], repo: httpsMatch[2] };
            }
        }
        catch {
            // Not a git repository
        }
        if (this.config.defaultOwner && this.config.defaultRepo) {
            return { owner: this.config.defaultOwner, repo: this.config.defaultRepo };
        }
        return null;
    }
    /**
     * Get repository info
     */
    async getRepository() {
        if (!this.repoInfo)
            return null;
        const endpoint = this.detectedPlatform === 'github'
            ? `/repos/${this.repoInfo.owner}/${this.repoInfo.repo}`
            : `/projects/${encodeURIComponent(`${this.repoInfo.owner}/${this.repoInfo.repo}`)}`;
        try {
            const data = await this.apiRequest('GET', endpoint);
            if (this.detectedPlatform === 'github') {
                const ghData = data;
                return {
                    id: ghData.id,
                    name: ghData.name,
                    fullName: ghData.full_name,
                    description: ghData.description || '',
                    url: ghData.html_url,
                    defaultBranch: ghData.default_branch,
                    private: ghData.private,
                    language: ghData.language ?? undefined,
                    stars: ghData.stargazers_count,
                    forks: ghData.forks_count,
                };
            }
            else {
                const glData = data;
                return {
                    id: glData.id,
                    name: glData.name,
                    fullName: glData.path_with_namespace,
                    description: glData.description || '',
                    url: glData.web_url,
                    defaultBranch: glData.default_branch,
                    private: glData.visibility === 'private',
                    language: glData.repository_language ?? undefined,
                    stars: glData.star_count,
                    forks: glData.forks_count,
                };
            }
        }
        catch (error) {
            logger.error('Failed to get repository', { error });
            return null;
        }
    }
    /**
     * List pull/merge requests
     */
    async listPullRequests(state = 'open') {
        if (!this.repoInfo)
            return [];
        const endpoint = this.detectedPlatform === 'github'
            ? `/repos/${this.repoInfo.owner}/${this.repoInfo.repo}/pulls?state=${state}`
            : `/projects/${encodeURIComponent(`${this.repoInfo.owner}/${this.repoInfo.repo}`)}/merge_requests?state=${state === 'all' ? 'all' : state === 'closed' ? 'merged' : 'opened'}`;
        try {
            const data = await this.apiRequest('GET', endpoint);
            return data.map((pr) => this.parsePullRequest(pr));
        }
        catch (error) {
            logger.error('Failed to list pull requests', { error });
            return [];
        }
    }
    /**
     * Get pull/merge request details
     */
    async getPullRequest(number) {
        if (!this.repoInfo)
            return null;
        const endpoint = this.detectedPlatform === 'github'
            ? `/repos/${this.repoInfo.owner}/${this.repoInfo.repo}/pulls/${number}`
            : `/projects/${encodeURIComponent(`${this.repoInfo.owner}/${this.repoInfo.repo}`)}/merge_requests/${number}`;
        try {
            const data = await this.apiRequest('GET', endpoint);
            return this.parsePullRequest(data);
        }
        catch (error) {
            logger.error('Failed to get pull request', { error });
            return null;
        }
    }
    /**
     * Create pull/merge request
     */
    async createPullRequest(options) {
        if (!this.repoInfo)
            return null;
        const endpoint = this.detectedPlatform === 'github'
            ? `/repos/${this.repoInfo.owner}/${this.repoInfo.repo}/pulls`
            : `/projects/${encodeURIComponent(`${this.repoInfo.owner}/${this.repoInfo.repo}`)}/merge_requests`;
        const body = this.detectedPlatform === 'github'
            ? {
                title: options.title,
                body: options.description,
                head: options.sourceBranch,
                base: options.targetBranch,
                draft: options.draft || false,
            }
            : {
                title: options.title,
                description: options.description,
                source_branch: options.sourceBranch,
                target_branch: options.targetBranch,
            };
        try {
            const data = await this.apiRequest('POST', endpoint, body);
            return this.parsePullRequest(data);
        }
        catch (error) {
            logger.error('Failed to create pull request', { error });
            return null;
        }
    }
    /**
     * List issues
     */
    async listIssues(state = 'open') {
        if (!this.repoInfo)
            return [];
        const endpoint = this.detectedPlatform === 'github'
            ? `/repos/${this.repoInfo.owner}/${this.repoInfo.repo}/issues?state=${state}`
            : `/projects/${encodeURIComponent(`${this.repoInfo.owner}/${this.repoInfo.repo}`)}/issues?state=${state === 'all' ? '' : state === 'closed' ? 'closed' : 'opened'}`;
        try {
            const data = await this.apiRequest('GET', endpoint);
            return data
                .filter((issue) => {
                // GitHub includes PRs in issues
                const ghIssue = issue;
                return !ghIssue.pull_request;
            })
                .map((issue) => this.parseIssue(issue));
        }
        catch (error) {
            logger.error('Failed to list issues', { error });
            return [];
        }
    }
    /**
     * Create issue
     */
    async createIssue(options) {
        if (!this.repoInfo)
            return null;
        const endpoint = this.detectedPlatform === 'github'
            ? `/repos/${this.repoInfo.owner}/${this.repoInfo.repo}/issues`
            : `/projects/${encodeURIComponent(`${this.repoInfo.owner}/${this.repoInfo.repo}`)}/issues`;
        const body = this.detectedPlatform === 'github'
            ? {
                title: options.title,
                body: options.description,
                labels: options.labels,
                assignees: options.assignees,
            }
            : {
                title: options.title,
                description: options.description,
                labels: options.labels?.join(','),
                assignee_ids: options.assignees,
            };
        try {
            const data = await this.apiRequest('POST', endpoint, body);
            return this.parseIssue(data);
        }
        catch (error) {
            logger.error('Failed to create issue', { error });
            return null;
        }
    }
    /**
     * Get CI status for a commit
     */
    async getCIStatus(sha) {
        if (!this.repoInfo)
            return [];
        const endpoint = this.detectedPlatform === 'github'
            ? `/repos/${this.repoInfo.owner}/${this.repoInfo.repo}/commits/${sha}/status`
            : `/projects/${encodeURIComponent(`${this.repoInfo.owner}/${this.repoInfo.repo}`)}/pipelines?sha=${sha}`;
        try {
            if (this.detectedPlatform === 'github') {
                const data = await this.apiRequest('GET', endpoint);
                return (data.statuses || []).map((status) => ({
                    state: this.mapState(status.state),
                    context: status.context,
                    description: status.description || '',
                    url: status.target_url ?? undefined,
                    createdAt: new Date(status.created_at),
                }));
            }
            else {
                const data = await this.apiRequest('GET', endpoint);
                return data.map((pipeline) => ({
                    state: this.mapState(pipeline.status),
                    context: `Pipeline #${pipeline.id}`,
                    description: pipeline.ref || '',
                    url: pipeline.web_url ?? undefined,
                    createdAt: new Date(pipeline.created_at),
                }));
            }
        }
        catch (error) {
            logger.error('Failed to get CI status', { error });
            return [];
        }
    }
    /**
     * Get recent commits
     */
    async getCommits(branch, limit = 10) {
        if (!this.repoInfo)
            return [];
        const branchParam = branch ? `sha=${branch}` : '';
        const endpoint = this.detectedPlatform === 'github'
            ? `/repos/${this.repoInfo.owner}/${this.repoInfo.repo}/commits?${branchParam}&per_page=${limit}`
            : `/projects/${encodeURIComponent(`${this.repoInfo.owner}/${this.repoInfo.repo}`)}/repository/commits?ref_name=${branch || ''}&per_page=${limit}`;
        try {
            const data = await this.apiRequest('GET', endpoint);
            return data.map((commit) => {
                if (this.detectedPlatform === 'github') {
                    const ghCommit = commit;
                    return {
                        sha: ghCommit.sha,
                        message: ghCommit.commit.message,
                        author: ghCommit.commit.author.name,
                        date: new Date(ghCommit.commit.author.date),
                        url: ghCommit.html_url,
                    };
                }
                else {
                    const glCommit = commit;
                    return {
                        sha: glCommit.id,
                        message: glCommit.message,
                        author: glCommit.author_name,
                        date: new Date(glCommit.created_at),
                        url: glCommit.web_url,
                    };
                }
            });
        }
        catch (error) {
            logger.error('Failed to get commits', { error });
            return [];
        }
    }
    /**
     * Add comment to issue or PR
     */
    async addComment(number, body, isPullRequest = false) {
        if (!this.repoInfo)
            return false;
        const endpoint = this.detectedPlatform === 'github'
            ? `/repos/${this.repoInfo.owner}/${this.repoInfo.repo}/issues/${number}/comments`
            : isPullRequest
                ? `/projects/${encodeURIComponent(`${this.repoInfo.owner}/${this.repoInfo.repo}`)}/merge_requests/${number}/notes`
                : `/projects/${encodeURIComponent(`${this.repoInfo.owner}/${this.repoInfo.repo}`)}/issues/${number}/notes`;
        try {
            await this.apiRequest('POST', endpoint, { body });
            return true;
        }
        catch (error) {
            logger.error('Failed to add comment', { error });
            return false;
        }
    }
    /**
     * Make API request
     */
    async apiRequest(method, endpoint, body) {
        const url = `${this.config.baseUrl}${endpoint}`;
        const headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
        };
        if (this.config.token) {
            if (this.detectedPlatform === 'github') {
                headers['Authorization'] = `Bearer ${this.config.token}`;
            }
            else {
                headers['PRIVATE-TOKEN'] = this.config.token;
            }
        }
        const response = await fetch(url, {
            method,
            headers,
            body: body ? JSON.stringify(body) : undefined,
        });
        if (!response.ok) {
            throw new Error(`API error: ${response.status} ${response.statusText}`);
        }
        return await response.json();
    }
    /**
     * Parse pull request response
     */
    parsePullRequest(data) {
        if (this.detectedPlatform === 'github') {
            return {
                id: data.id,
                number: data.number,
                title: data.title,
                description: data.body || '',
                state: data.merged ? 'merged' : data.state,
                author: data.user.login,
                sourceBranch: data.head.ref,
                targetBranch: data.base.ref,
                url: data.html_url,
                createdAt: new Date(data.created_at),
                updatedAt: new Date(data.updated_at),
                labels: (data.labels || []).map(l => l.name),
                reviewers: (data.requested_reviewers || []).map(r => r.login),
                draft: data.draft || false,
            };
        }
        else {
            return {
                id: data.id,
                number: data.iid,
                title: data.title,
                description: data.description || '',
                state: data.state === 'merged' ? 'merged' : data.state === 'closed' ? 'closed' : 'open',
                author: data.author.username,
                sourceBranch: data.source_branch,
                targetBranch: data.target_branch,
                url: data.web_url,
                createdAt: new Date(data.created_at),
                updatedAt: new Date(data.updated_at),
                labels: data.labels || [],
                reviewers: (data.reviewers || []).map(r => r.username),
                draft: data.draft || false,
            };
        }
    }
    /**
     * Parse issue response
     */
    parseIssue(data) {
        if (this.detectedPlatform === 'github') {
            return {
                id: data.id,
                number: data.number,
                title: data.title,
                description: data.body || '',
                state: data.state,
                author: data.user.login,
                url: data.html_url,
                createdAt: new Date(data.created_at),
                updatedAt: new Date(data.updated_at),
                labels: (data.labels || []).map(l => l.name),
                assignees: (data.assignees || []).map(a => a.login),
                milestone: data.milestone?.title,
            };
        }
        else {
            return {
                id: data.id,
                number: data.iid,
                title: data.title,
                description: data.description || '',
                state: data.state,
                author: data.author.username,
                url: data.web_url,
                createdAt: new Date(data.created_at),
                updatedAt: new Date(data.updated_at),
                labels: data.labels || [],
                assignees: (data.assignees || []).map(a => a.username),
                milestone: data.milestone?.title,
            };
        }
    }
    /**
     * Map CI state
     */
    mapState(state) {
        const stateMap = {
            pending: 'pending',
            running: 'running',
            success: 'success',
            passed: 'success',
            failure: 'failure',
            failed: 'failure',
            error: 'failure',
            cancelled: 'cancelled',
            canceled: 'cancelled',
            skipped: 'cancelled',
        };
        return stateMap[state.toLowerCase()] || 'pending';
    }
}
// Singleton instance
let gitPlatform = null;
/**
 * Get or create git platform integration
 */
export function getGitPlatform(config) {
    if (!gitPlatform) {
        gitPlatform = new GitPlatformIntegration(config || { platform: 'auto' });
        gitPlatform.init().catch((err) => {
            logger.debug('Failed to initialize git platform', { error: err instanceof Error ? err.message : String(err) });
        });
    }
    return gitPlatform;
}
export default GitPlatformIntegration;
//# sourceMappingURL=git-platform-integration.js.map