import { db } from "../db.ts";
import { users } from "../../drizzle/schema.ts";
import { eq } from "drizzle-orm";
import crypto from "crypto";

export interface OAuthProvider {
  name: "google" | "github" | "apple";
  clientId: string;
  clientSecret: string;
  redirectUri: string;
}

export interface OAuthConfig {
  google?: OAuthProvider;
  github?: OAuthProvider;
  apple?: OAuthProvider;
}

export class SocialOAuthService {
  private static config: OAuthConfig = {};

  /**
   * Initialize OAuth configuration
   */
  static initialize(config: OAuthConfig) {
    this.config = config;
  }

  /**
   * Generate OAuth authorization URL
   */
  static getAuthorizationUrl(provider: "google" | "github" | "apple", state?: string): string {
    const providerConfig = this.config[provider];
    if (!providerConfig) {
      throw new Error(`OAuth provider ${provider} not configured`);
    }

    const stateParam = state || crypto.randomBytes(16).toString("hex");
    const params = new URLSearchParams({
      client_id: providerConfig.clientId,
      redirect_uri: providerConfig.redirectUri,
      response_type: "code",
      state: stateParam,
    });

    switch (provider) {
      case "google":
        params.append("scope", "openid profile email");
        return `https://accounts.google.com/o/oauth2/v2/auth?${params}`;

      case "github":
        params.append("scope", "user:email");
        return `https://github.com/login/oauth/authorize?${params}`;

      case "apple":
        params.append("response_mode", "form_post");
        return `https://appleid.apple.com/auth/authorize?${params}`;

      default:
        throw new Error(`Unknown OAuth provider: ${provider}`);
    }
  }

  /**
   * Exchange authorization code for access token
   */
  static async exchangeCodeForToken(
    provider: "google" | "github" | "apple",
    code: string,
    state: string
  ): Promise<{ accessToken: string; refreshToken?: string; expiresIn: number }> {
    const providerConfig = this.config[provider];
    if (!providerConfig) {
      throw new Error(`OAuth provider ${provider} not configured`);
    }

    // In production, make actual HTTP request to provider's token endpoint
    console.log(`[OAuth] Exchanging code for ${provider} token`);

    // Placeholder response
    return {
      accessToken: crypto.randomBytes(32).toString("hex"),
      refreshToken: crypto.randomBytes(32).toString("hex"),
      expiresIn: 3600,
    };
  }

  /**
   * Get user info from OAuth provider
   */
  static async getUserInfo(
    provider: "google" | "github" | "apple",
    accessToken: string
  ): Promise<{
    id: string;
    email: string;
    name: string;
    picture?: string;
  }> {
    // In production, make actual HTTP request to provider's user info endpoint
    console.log(`[OAuth] Fetching user info from ${provider}`);

    // Placeholder response
    return {
      id: crypto.randomBytes(16).toString("hex"),
      email: `user@${provider}.com`,
      name: `${provider} User`,
      picture: `https://via.placeholder.com/150?text=${provider}`,
    };
  }

  /**
   * Link OAuth account to existing user
   */
  static async linkOAuthAccount(
    userId: number,
    provider: "google" | "github" | "apple",
    oauthId: string,
    accessToken: string
  ) {
    // In production, store OAuth account link in database
    console.log(`[OAuth] Linking ${provider} account ${oauthId} to user ${userId}`);

    return {
      success: true,
      provider,
      linkedAt: new Date().toISOString(),
    };
  }

  /**
   * Find or create user from OAuth
   */
  static async findOrCreateUser(
    provider: "google" | "github" | "apple",
    oauthId: string,
    email: string,
    name: string,
    picture?: string
  ) {
    // Try to find existing user by email
    const dbInstance = await db();
    if (!dbInstance) {
      throw new Error('Database connection failed');
    }
    
    const userResult = await dbInstance
      .select()
      .from(users)
      .where(eq(users.email, email))
      .limit(1);
    
    let user = userResult[0] || null;

    if (user) {
      // Link OAuth account to existing user
      await this.linkOAuthAccount(user.id, provider, oauthId, "");
      return user;
    }

    // Create new user
    // In production, use proper user creation flow
    console.log(`[OAuth] Creating new user from ${provider}: ${email}`);

    return {
      id: Math.floor(Math.random() * 1000000),
      email,
      name,
      loginMethod: provider,
    };
  }

  /**
   * Revoke OAuth access
   */
  static async revokeAccess(provider: "google" | "github" | "apple", accessToken: string) {
    // In production, make actual HTTP request to provider's revoke endpoint
    console.log(`[OAuth] Revoking ${provider} access`);

    return { success: true };
  }

  /**
   * Validate OAuth state parameter
   */
  static validateState(state: string, expectedState: string): boolean {
    return state === expectedState;
  }
}
