import { ILogger, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
import axios, { AxiosRequestConfig } from 'axios';
import {
  NotificationProvider,
  NotificationProviderSendParams,
  NotificationProviderSendResult,
} from '../../types';
import {
  DEFAULT_FEISHU_APP_CONFIG,
  DEFAULT_NOTIFICATION_TIMEOUT,
} from '../constants';

interface FeishuTokenCache {
  token: string;
  expireAt: number;
}

export interface FeishuDepartmentItem {
  department_id?: string;
  open_department_id?: string;
  name?: string;
  parent_department_id?: string;
  chat_id?: string;
  leader_user_id?: string;
  member_count?: number;
  primary_member_count?: number;
  status?: Record<string, any>;
}

export interface FeishuDepartmentUserItem {
  union_id?: string;
  user_id?: string;
  open_id?: string;
  name?: string;
  en_name?: string;
  email?: string;
  mobile?: string;
  employee_no?: string;
  avatar?: {
    avatar_72?: string;
    avatar_240?: string;
    avatar_640?: string;
    avatar_origin?: string;
  };
  status?: Record<string, any>;
  department_ids?: string[];
  leader_user_id?: string;
  city?: string;
  country?: string;
  work_station?: string;
  join_time?: number;
}

@Provide()
@Scope(ScopeEnum.Singleton)
export class FeishuNotificationProvider implements NotificationProvider {
  @Inject()
  logger: ILogger;

  readonly platform = 'feishu';

  private tokenCache = new Map<string, FeishuTokenCache>();

  async send(
    params: NotificationProviderSendParams
  ): Promise<NotificationProviderSendResult> {
    const appId = params.appId || DEFAULT_FEISHU_APP_CONFIG.appId;
    const appSecret = params.appSecret || DEFAULT_FEISHU_APP_CONFIG.appSecret;

    if (!appId || !appSecret) {
      return {
        success: false,
        platform: this.platform,
        errorMessage: '飞书应用配置缺失: appId/appSecret不能为空',
      };
    }

    const accessToken = await this.getTenantAccessToken(appId, appSecret);
    const contentText = this.buildTextContent(
      params.title,
      params.message,
      params.mentionAll
    );
    const payload = {
      receive_id: params.receiveId,
      msg_type: 'text',
      content: JSON.stringify({ text: contentText }),
    };
    const requestUrl = `https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=${encodeURIComponent(
      params.receiveIdType || 'open_id'
    )}`;

    try {
      const response = await this.requestFeishuApi(requestUrl, {
        method: 'POST',
        data: payload,
        headers: {
          Authorization: `Bearer ${accessToken}`,
          'Content-Type': 'application/json',
        },
      });
      const data = response || {};
      const messageId = data?.data?.message_id;
      const success = data.code === 0;

      return {
        success,
        platform: this.platform,
        externalMessageId: messageId,
        requestId: params.requestId,
        providerCode: data.code,
        providerMessage: data.msg,
        providerPayload: payload,
        providerResponse: data,
        errorMessage: success ? undefined : data.msg || '飞书消息发送失败',
      };
    } catch (error: any) {
      return {
        success: false,
        platform: this.platform,
        providerCode: error?.code,
        providerMessage: error?.message,
        providerPayload: payload,
        providerResponse: error?.response,
        errorMessage: error?.message || '飞书消息发送失败',
      };
    }
  }

  async listDepartmentChildren(options: {
    departmentId: string;
    departmentIdType?: 'department_id' | 'open_department_id';
    pageSize?: number;
    pageToken?: string;
    fetchChild?: boolean;
    appId?: string;
    appSecret?: string;
    accessToken?: string;
  }): Promise<{
    items: FeishuDepartmentItem[];
    hasMore: boolean;
    pageToken?: string;
  }> {
    const appId = options.appId || DEFAULT_FEISHU_APP_CONFIG.appId;
    const appSecret = options.appSecret || DEFAULT_FEISHU_APP_CONFIG.appSecret;
    const accessToken =
      options.accessToken ||
      (await this.getTenantAccessToken(appId, appSecret));
    const searchParams = new URLSearchParams({
      department_id_type: options.departmentIdType || 'department_id',
      fetch_child: String(options.fetchChild ?? false),
      page_size: String(options.pageSize || 50),
    });
    if (options.pageToken) {
      searchParams.set('page_token', options.pageToken);
    }
    const requestUrl = `https://open.feishu.cn/open-apis/contact/v3/departments/${encodeURIComponent(
      options.departmentId
    )}/children?${searchParams.toString()}`;

    const data = await this.requestFeishuApi(requestUrl, {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${accessToken}`,
        'Content-Type': 'application/json; charset=utf-8',
      },
    });

    return {
      items: data?.data?.items || [],
      hasMore: Boolean(data?.data?.has_more),
      pageToken: data?.data?.page_token,
    };
  }

  async listUsersByDepartment(options: {
    departmentId: string;
    departmentIdType?: 'department_id' | 'open_department_id';
    userIdType?: 'open_id' | 'union_id' | 'user_id';
    pageSize?: number;
    pageToken?: string;
    appId?: string;
    appSecret?: string;
    accessToken?: string;
  }): Promise<{
    items: FeishuDepartmentUserItem[];
    hasMore: boolean;
    pageToken?: string;
  }> {
    const appId = options.appId || DEFAULT_FEISHU_APP_CONFIG.appId;
    const appSecret = options.appSecret || DEFAULT_FEISHU_APP_CONFIG.appSecret;
    const accessToken =
      options.accessToken ||
      (await this.getTenantAccessToken(appId, appSecret));
    const searchParams = new URLSearchParams({
      department_id: options.departmentId,
      department_id_type: options.departmentIdType || 'department_id',
      user_id_type: options.userIdType || 'open_id',
      page_size: String(options.pageSize || 50),
    });
    if (options.pageToken) {
      searchParams.set('page_token', options.pageToken);
    }
    const requestUrl = `https://open.feishu.cn/open-apis/contact/v3/users/find_by_department?${searchParams.toString()}`;

    const data = await this.requestFeishuApi(requestUrl, {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${accessToken}`,
        'Content-Type': 'application/json; charset=utf-8',
      },
    });

    return {
      items: data?.data?.items || [],
      hasMore: Boolean(data?.data?.has_more),
      pageToken: data?.data?.page_token,
    };
  }

  private buildTextContent(
    title?: string,
    message?: string,
    mentionAll?: boolean
  ) {
    const lines = [];
    if (title) {
      lines.push(`【${title}】`);
    }
    if (message) {
      lines.push(message);
    }
    if (mentionAll) {
      lines.push('<at user_id="all">所有人</at>');
    }
    return lines.join('\n');
  }

  private async getTenantAccessToken(appId: string, appSecret: string) {
    const cacheKey = `${appId}:${appSecret}`;
    const cached = this.tokenCache.get(cacheKey);
    const now = Date.now();
    if (cached && cached.expireAt > now + 60_000) {
      return cached.token;
    }

    const response = await this.requestFeishuApi(
      'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal',
      {
        method: 'POST',
        data: {
          app_id: appId,
          app_secret: appSecret,
        },
        headers: {
          'Content-Type': 'application/json',
        },
      }
    );

    if (response.code !== 0 || !response.tenant_access_token) {
      throw new Error(response.msg || '获取飞书tenant_access_token失败');
    }

    const expireAt = now + Number(response.expire || 7200) * 1000;
    this.tokenCache.set(cacheKey, {
      token: response.tenant_access_token,
      expireAt,
    });
    return response.tenant_access_token;
  }

  private async requestFeishuApi(url: string, config: AxiosRequestConfig) {
    try {
      const response = await axios({
        url,
        timeout: DEFAULT_NOTIFICATION_TIMEOUT,
        validateStatus: () => true,
        ...config,
      });
      const data = response.data || {};
      if (response.status >= 400 || data.code !== 0) {
        const error = {
          status: response.status,
          code: data.code,
          message: data.msg || `Feishu API请求失败: HTTP ${response.status}`,
          response: data,
          url,
        };
        this.logger.error(
          `[Notification][Feishu] API失败: url=${url}, status=${response.status}, code=${data.code}, msg=${data.msg}`
        );
        throw error;
      }
      return data;
    } catch (error: any) {
      if (error?.response || error?.code || error?.status) {
        throw error;
      }
      this.logger.error(
        `[Notification][Feishu] 网络请求异常: url=${url}, message=${error.message}`,
        error
      );
      throw {
        status: error?.response?.status,
        code: error?.response?.data?.code || error?.code,
        message: error?.response?.data?.msg || error.message,
        response: error?.response?.data,
        url,
      };
    }
  }
}

