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 GoogleProvider extends BaseOAuthProvider {

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

  getProviderType() {
    return 'GOOGLE';
  }

  async getAuthUrl(callbackPath: string) {

    const settings = await this.setting.getSettingValues([
      'google_client_id',
      'google_client_secret',
      'google_scopes',
      'url',
    ]);

    const redirectURI = new URL(callbackPath, settings['url']).toString();

    const params = new URLSearchParams({
      client_id: settings['google_client_id'],
      redirect_uri: redirectURI,
      response_type: 'code',
      scope: (settings['google_scopes'] ?? []).join(' '),
      access_type: 'offline',
      prompt: 'consent',
    });

    return `https://accounts.google.com/o/oauth2/v2/auth?${params}`;
  }

  async getProfile(code: string, type: string) {

    const settings = await this.setting.getSettingValues([
      'google_client_id',
      'google_client_secret',
      'google_scopes',
      'url',
    ]);

    const token = await this.fetchToken({
      code,
      url: 'https://oauth2.googleapis.com/token',
      clientId: settings['google_client_id'],
      clientSecret: settings['google_client_secret'],
      redirectUri: `${settings['url']}/callback/google/${type}`,
    });

    const basicProfile = await this.fetchProfile(
      token.access_token,
      'https://www.googleapis.com/oauth2/v2/userinfo',
    );

    const peopleProfile = await this.getGoogleProfileFromAccessToken(
      token.access_token,
    );
    
    return {
      ...basicProfile,
      gender: peopleProfile.gender,
      birthday: peopleProfile.birthday,
      oauth_tokens: {
        access_token: token.access_token,
        refresh_token: token.refresh_token,
        expires_in: token.expires_in,
        token_type: token.token_type,
      },
    };
  }

  private async getGoogleProfileFromAccessToken(accessToken: string) {
    const url =
      'https://people.googleapis.com/v1/people/me?personFields=genders,birthdays';

    const res = await fetch(url, {
      headers: {
        Authorization: `Bearer ${accessToken}`,
      },
    });

    if (!res.ok) {
      throw new Error(`Google People API error: ${res.statusText}`);
    }

    const data: any = await res.json();

    const gender =
      data.genders?.find((g: any) => g.metadata?.primary)?.value ??
      data.genders?.[0]?.value ??
      null;

    const b =
      data.birthdays?.find((x: any) => x.metadata?.primary) ??
      data.birthdays?.[0];

    const date = b?.date
      ? { day: b.date.day, month: b.date.month, year: b.date.year ?? null }
      : null;

    return { gender, birthday: date, raw: data };
  }
}
