import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from '../entities/user.entity';

interface WeComTokenResponse {
  errcode: number;
  errmsg: string;
  access_token: string;
  expires_in: number;
}

interface WeComDeptListResponse {
  errcode: number;
  errmsg: string;
  department: Array<{ id: number; name: string; parentid: number }>;
}

interface WeComUserListResponse {
  errcode: number;
  errmsg: string;
  userlist: Array<{
    userid: string;
    name: string;
    mobile: string;
    department: number[];
  }>;
}

@Injectable()
export class WeComService {
  private readonly logger = new Logger(WeComService.name);
  private accessToken: string | null = null;
  private tokenExpiresAt = 0;

  constructor(
    @InjectRepository(User)
    private readonly userRepo: Repository<User>,
  ) {}

  private get configured(): boolean {
    return !!(process.env.WECOM_CORP_ID && process.env.WECOM_CORP_SECRET);
  }

  private async getAccessToken(): Promise<string> {
    if (this.accessToken && Date.now() < this.tokenExpiresAt - 60_000) {
      return this.accessToken;
    }
    const corpId = process.env.WECOM_CORP_ID!;
    const corpSecret = process.env.WECOM_CORP_SECRET!;
    const url = `https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpId}&corpsecret=${corpSecret}`;
    const res = await fetch(url);
    const body: WeComTokenResponse = await res.json();
    if (body.errcode !== 0) {
      throw new Error(`WeCom gettoken failed: ${body.errmsg} (${body.errcode})`);
    }
    this.accessToken = body.access_token;
    this.tokenExpiresAt = Date.now() + body.expires_in * 1000;
    return this.accessToken;
  }

  private async fetchDepartments(
    token: string,
    parentId = 1,
  ): Promise<Array<{ id: number; name: string; parentid: number }>> {
    const all: WeComDeptListResponse['department'] = [];
    const url = `https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=${token}&id=${parentId}`;
    const res = await fetch(url);
    const body: WeComDeptListResponse = await res.json();
    if (body.errcode !== 0) {
      if (body.errcode === 60003) return all;
      throw new Error(`WeCom department list failed: ${body.errmsg} (${body.errcode})`);
    }
    for (const dept of body.department) {
      all.push(dept);
      if (dept.id !== parentId) {
        const children = await this.fetchDepartments(token, dept.id);
        all.push(...children);
      }
    }
    return all;
  }

  private async fetchUsers(
    token: string,
    deptId: number,
  ): Promise<Array<{ userid: string; name: string; mobile: string; department: number[] }>> {
    const url = `https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?access_token=${token}&department_id=${deptId}&fetch_child=1`;
    const res = await fetch(url);
    const body: WeComUserListResponse = await res.json();
    if (body.errcode !== 0) {
      throw new Error(`WeCom user list failed: ${body.errmsg} (${body.errcode})`);
    }
    return body.userlist;
  }

  async syncAll(): Promise<{ userCount: number }> {
    if (!this.configured) {
      this.logger.warn('WeCom not configured (WECOM_CORP_ID / WECOM_CORP_SECRET missing), skipping sync');
      return { userCount: 0 };
    }
    const token = await this.getAccessToken();
    const wxDepts = await this.fetchDepartments(token);

    let userCount = 0;
    const seenUserIds = new Set<string>();
    for (const wd of wxDepts) {
      const wxUsers = await this.fetchUsers(token, wd.id);
      for (const wu of wxUsers) {
        if (seenUserIds.has(wu.userid)) continue;
        seenUserIds.add(wu.userid);
        let user = await this.userRepo.findOne({ where: { username: wu.userid } });
        if (user) {
          user.name = wu.name;
        } else {
          user = this.userRepo.create({
            username: wu.userid,
            name: wu.name,
            passwordHash: '',
            isActive: true,
          });
          userCount++;
        }
        await this.userRepo.save(user);
      }
    }

    this.logger.log(`WeCom sync done: ${userCount} new users`);
    return { userCount };
  }
}
