import { HttpService } from '@nestjs/axios';
import { forwardRef, Inject, Injectable } from '@nestjs/common';
import { SettingService } from '../../setting/setting.service';
import { BaseOAuthProvider } from './abstract.provider';

@Injectable()
export class GithubProvider
  extends BaseOAuthProvider {

  constructor(
    http: HttpService,
    @Inject(forwardRef(() => SettingService))
    private readonly setting: SettingService,
  ) {
    super(http);
  }

  getProviderType() {
    return 'GITHUB';
  }

  async getAuthUrl(callbackPath: string) {

    const settings = await this.setting.getSettingValues([
      'github_client_id',
      'github_client_secret',
      'github_scopes',
      'api-url',
    ]);

    const fixedCallbackPath = '/oauth/github/callback';
    const redirectURI = new URL(fixedCallbackPath, settings['api-url']).toString();
    const scopes = settings['github_scopes'];
    const type = callbackPath.split('/').pop() || 'login';
    const params = new URLSearchParams({
      client_id: settings['github_client_id'],
      redirect_uri: redirectURI,
      scope: scopes.join(' '),
      allow_signup: 'true',
      state: type,
    });

    return `https://github.com/login/oauth/authorize?${params.toString()}`;
  }

  async getProfile(code: string) {
    const settings = await this.setting.getSettingValues([
      'github_client_id',
      'github_client_secret',
      'github_scopes',
      'api-url',
    ]);

    const fixedCallbackPath = '/oauth/github/callback';
    const redirectURI = new URL(fixedCallbackPath, settings['api-url'].replace(":3200", ":3100")).toString();
    const tokenResponse = await this.http.axiosRef.post(
      'https://github.com/login/oauth/access_token',
      {
        client_id: settings['github_client_id'],
        client_secret: settings['github_client_secret'],
        code,
        redirect_uri: redirectURI,
      },
      {
        headers: {
          Accept: 'application/json',
        },
      },
    );

    const { access_token, error, error_description } = tokenResponse.data;
    if (error || !access_token) {
      throw new Error(
        `GitHub OAuth error: ${error_description || error || 'No access token received'}`,
      );
    }

    const profileResponse = await this.http.axiosRef.get(
      'https://api.github.com/user',
      {
        headers: {
          Authorization: `Bearer ${access_token}`,
        },
      },
    );

    const profile = profileResponse.data;
    let email = profile.email;
    if (!email) {
      const emailResponse = await this.http.axiosRef.get(
        'https://api.github.com/user/emails',
        {
          headers: {
            Authorization: `Bearer ${access_token}`,
          },
        },
      );
      const primaryEmail = emailResponse.data.find(
        (e: any) => e.primary && e.verified,
      );
      email = primaryEmail?.email || null;
    }

    return {
      id: profile.id.toString(),
      email,
      name: profile.name || profile.login,
      picture: profile.avatar_url,
      oauth_tokens: {
        access_token: access_token,
        refresh_token: access_token,
        expires_in: null,
        token_type: 'bearer',
      },
    };
  }
}