/**
 * GitHub OAuth integration for VIBN
 * Allows users to connect their GitHub account for repo analysis and tracking
 */

export interface GitHubUser {
  id: number;
  login: string;
  name: string | null;
  email: string | null;
  avatar_url: string;
}

export interface GitHubRepo {
  id: number;
  name: string;
  full_name: string;
  description: string | null;
  html_url: string;
  language: string | null;
  default_branch: string;
  private: boolean;
  topics: string[];
}

export interface GitHubConnection {
  userId: string;
  githubUserId: number;
  githubUsername: string;
  accessToken: string; // Encrypted
  refreshToken?: string; // Encrypted
  tokenExpiresAt?: Date;
  scopes: string[];
  connectedAt: Date;
  lastSyncedAt?: Date;
}

/**
 * Initiates GitHub OAuth flow
 * Redirects user to GitHub authorization page
 */
export function initiateGitHubOAuth(redirectUri: string) {
  const clientId = process.env.NEXT_PUBLIC_GITHUB_CLIENT_ID;
  
  if (!clientId) {
    throw new Error('GitHub OAuth not configured');
  }

  // Scopes we need:
  // - repo: Access repositories (read commits, PRs, issues)
  // - read:user: Get user profile
  const scopes = ['repo', 'read:user'];
  
  // Generate state for CSRF protection
  const state = generateRandomString(32);
  sessionStorage.setItem('github_oauth_state', state);
  
  const params = new URLSearchParams({
    client_id: clientId,
    redirect_uri: redirectUri,
    scope: scopes.join(' '),
    state,
  });

  window.location.href = `https://github.com/login/oauth/authorize?${params}`;
}

/**
 * Exchanges authorization code for access token
 */
export async function exchangeCodeForToken(code: string): Promise<{
  access_token: string;
  token_type: string;
  scope: string;
}> {
  const response = await fetch('/api/github/oauth/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ code }),
  });

  if (!response.ok) {
    throw new Error('Failed to exchange code for token');
  }

  return response.json();
}

/**
 * Fetches GitHub user profile
 */
export async function getGitHubUser(accessToken: string): Promise<GitHubUser> {
  const response = await fetch('https://api.github.com/user', {
    headers: {
      Authorization: `Bearer ${accessToken}`,
      Accept: 'application/vnd.github.v3+json',
    },
  });

  if (!response.ok) {
    throw new Error('Failed to fetch GitHub user');
  }

  return response.json();
}

/**
 * Fetches user's repositories
 */
export async function getGitHubRepos(
  accessToken: string,
  options?: {
    sort?: 'created' | 'updated' | 'pushed' | 'full_name';
    direction?: 'asc' | 'desc';
    per_page?: number;
  }
): Promise<GitHubRepo[]> {
  const params = new URLSearchParams({
    sort: options?.sort || 'updated',
    direction: options?.direction || 'desc',
    per_page: String(options?.per_page || 100),
  });

  const response = await fetch(`https://api.github.com/user/repos?${params}`, {
    headers: {
      Authorization: `Bearer ${accessToken}`,
      Accept: 'application/vnd.github.v3+json',
    },
  });

  if (!response.ok) {
    throw new Error('Failed to fetch repositories');
  }

  return response.json();
}

/**
 * Fetches a specific repository
 */
export async function getGitHubRepo(
  accessToken: string,
  owner: string,
  repo: string
): Promise<GitHubRepo> {
  const response = await fetch(`https://api.github.com/repos/${owner}/${repo}`, {
    headers: {
      Authorization: `Bearer ${accessToken}`,
      Accept: 'application/vnd.github.v3+json',
    },
  });

  if (!response.ok) {
    throw new Error('Failed to fetch repository');
  }

  return response.json();
}

/**
 * Utility: Generate random string for state parameter
 */
function generateRandomString(length: number): string {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  let result = '';
  const randomValues = new Uint8Array(length);
  crypto.getRandomValues(randomValues);
  
  for (let i = 0; i < length; i++) {
    result += chars[randomValues[i] % chars.length];
  }
  
  return result;
}

