import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as fs from 'fs';
import * as https from 'https';
import axios, { AxiosInstance } from 'axios';

const TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1000; // 5 分钟提前刷新

/**
 * ADP OAuth2 + mTLS 认证。
 * - 凭证：ConfigService（ADP_CLIENT_ID / ADP_CLIENT_SECRET）
 * - 证书：从 ADP_CERT_PATH (PEM) + ADP_KEY_PATH 加载（pfx 部署时需 openssl pkcs12 -legacy 转 PEM，由部署脚本处理）
 * - Token 缓存：内存级，到期前 5 分钟自动刷新
 */
@Injectable()
export class AdpAuthService {
  private readonly logger = new Logger(AdpAuthService.name);
  private accessToken = '';
  private tokenExpireAt = 0;
  private cachedHttpsAgent: https.Agent | null = null;

  constructor(private readonly config: ConfigService) {}

  get clientId(): string {
    return this.config.get<string>('ADP_CLIENT_ID', '');
  }

  get clientSecret(): string {
    return this.config.get<string>('ADP_CLIENT_SECRET', '');
  }

  get certPath(): string {
    return this.config.get<string>('ADP_CERT_PATH', '/tmp/adp_cert.pem');
  }

  get keyPath(): string {
    return this.config.get<string>('ADP_KEY_PATH', 'certs/ADPKeys/Buffer/FaradayFuture_auth.key');
  }

  get tokenUrl(): string {
    return this.config.get<string>('ADP_TOKEN_URL', 'https://api.adp.com/auth/oauth/v2/token');
  }

  get apiBase(): string {
    return this.config.get<string>('ADP_API_BASE', 'https://api.adp.com');
  }

  get isEnabled(): boolean {
    return this.config.get<string>('ADP_SYNC_ENABLED', 'false') === 'true';
  }

  /** 凭证完整性预检（提示性，不抛错） */
  validateConfig(): { ok: boolean; missing: string[] } {
    const missing: string[] = [];
    if (!this.clientId) missing.push('ADP_CLIENT_ID');
    if (!this.clientSecret) missing.push('ADP_CLIENT_SECRET');
    if (!fs.existsSync(this.certPath)) missing.push(`cert file at ${this.certPath}`);
    if (!fs.existsSync(this.keyPath)) missing.push(`key file at ${this.keyPath}`);
    return { ok: missing.length === 0, missing };
  }

  private getHttpsAgent(): https.Agent {
    if (this.cachedHttpsAgent) return this.cachedHttpsAgent;
    const cert = fs.readFileSync(this.certPath);
    const key = fs.readFileSync(this.keyPath);
    this.cachedHttpsAgent = new https.Agent({ cert, key, keepAlive: true });
    return this.cachedHttpsAgent;
  }

  /** 获取 access token，自动缓存 + 到期刷新 */
  async getAccessToken(): Promise<string> {
    if (this.accessToken && Date.now() < this.tokenExpireAt - TOKEN_REFRESH_BUFFER_MS) {
      return this.accessToken;
    }

    const params = new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: this.clientId,
      client_secret: this.clientSecret,
    });

    try {
      const response = await axios.post(this.tokenUrl, params.toString(), {
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        httpsAgent: this.getHttpsAgent(),
        timeout: 30_000,
      });

      const { access_token, expires_in } = response.data as {
        access_token: string;
        expires_in: number;
      };

      if (!access_token) {
        throw new Error('ADP token response missing access_token');
      }

      this.accessToken = access_token;
      this.tokenExpireAt = Date.now() + (expires_in ?? 3600) * 1000;
      this.logger.debug(`ADP token 已刷新，过期时间 ${new Date(this.tokenExpireAt).toISOString()}`);
      return access_token;
    } catch (error: any) {
      this.logger.error(`ADP token 获取失败: ${error.message}`);
      throw new Error(`ADP_TOKEN_FAILED: ${error.message}`);
    }
  }

  /** 构造一个带 mTLS + Bearer 的 axios 实例 */
  async createHttpClient(): Promise<AxiosInstance> {
    const token = await this.getAccessToken();
    return axios.create({
      baseURL: this.apiBase,
      httpsAgent: this.getHttpsAgent(),
      headers: {
        Authorization: `Bearer ${token}`,
        Accept: 'application/json',
      },
      timeout: 60_000,
    });
  }
}
