import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
import type { WindowHandle } from './types.js';

/**
 * 截图器选项
 */
export interface CaptureOptions {
  /** 跳过最小化窗口（默认 true） */
  skipMinimized?: boolean;
  /** 多个匹配时取面积最大的（默认 true） */
  largest?: boolean;
}

/**
 * 基于 node-screenshots 的窗口截图服务
 *
 * 关键不变量:
 * 1. 每次 capture 都重新 enumerate Window.all() — 不缓存 Window 实例
 *    （PoC 发现 node-screenshots 在同一 Window 实例上 captureImageSync 缓存,
 *    必须重新枚举才能拿到新帧）
 * 2. 微信主窗口 appName === 'Weixin'（注意：title 是中文 '微信'）
 *
 * platform !== 'win32' 时抛 'unsupported-platform'。
 */
@Provide()
@Scope(ScopeEnum.Singleton)
export class NodeScreenshooter {
  /**
   * 按 appName 找窗口并截图（每次重新 enumerate）
   * 返回 PNG 字节流。
   * 找不到匹配窗口时抛 'window-not-found'。
   */
  captureWindowByAppName(appName: string, opts: CaptureOptions = {}): Buffer {
    if (process.platform !== 'win32') {
      throw new Error('unsupported-platform');
    }

    const skipMinimized = opts.skipMinimized ?? true;
    const largest = opts.largest ?? true;

    // 动态 require 避免在非 Windows CI 环境下 import 原生模块失败
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    const ns = require('node-screenshots') as { Window: { all(): Array<any> } };

    // ★ v4 修复:node-screenshots 暴露的是 getter 方法,通过 readProp 兼容字段与方法两种形式
    const readProp = (w: any, key: string): any => {
      const v = w?.[key];
      if (typeof v === 'function') {
        try { return v.call(w); } catch { return undefined; }
      }
      const snake = key.replace(/[A-Z]/g, ch => '_' + ch.toLowerCase());
      const v2 = w?.[snake];
      if (typeof v2 === 'function') {
        try { return v2.call(w); } catch { return undefined; }
      }
      return v ?? v2;
    };

    // 每次重新枚举,不复用旧 Window 实例(否则 captureImageSync 返回缓存帧)
    const all = ns.Window.all();
    const needle = appName.toLowerCase();
    let candidates = all.filter(w => {
      const an = String(readProp(w, 'appName') ?? '').toLowerCase();
      const ti = String(readProp(w, 'title') ?? '').toLowerCase();
      return an === needle
        || an.includes(needle)
        || ti.includes(needle)
        || (appName === 'Weixin' && (ti.includes('微信') || an.includes('微信')));
    });

    if (skipMinimized) {
      candidates = candidates.filter(w => !readProp(w, 'isMinimized'));
    }

    candidates = candidates.filter(w => {
      const wv = Number(readProp(w, 'width') ?? 0);
      const hv = Number(readProp(w, 'height') ?? 0);
      return wv > 0 && hv > 0;
    });

    if (candidates.length === 0) {
      throw new Error('window-not-found');
    }

    // 多个匹配窗口时取面积最大的
    if (largest && candidates.length > 1) {
      candidates.sort((a, b) => {
        const aArea = Number(readProp(a, 'width') ?? 0) * Number(readProp(a, 'height') ?? 0);
        const bArea = Number(readProp(b, 'width') ?? 0) * Number(readProp(b, 'height') ?? 0);
        return bArea - aArea;
      });
    }

    const win = candidates[0];
    const image = win.captureImageSync();
    return image.toPngSync() as Buffer;
  }

  /**
   * 用已有的 WindowHandle 截图（每次重新 enumerate 找回 Window 实例）
   * 不复用 handle.nsWindow，因为可能已被 GC 或持有缓存帧。
   */
  captureWindow(handle: WindowHandle): Buffer {
    if (process.platform !== 'win32') {
      throw new Error('unsupported-platform');
    }
    return this.captureWindowByAppName(handle.appName, {
      skipMinimized: true,
      largest: true,
    });
  }

  /**
   * 全屏截图（MVP 暂不用，留接口备用）
   * 取第一块显示器。
   */
  captureFullScreen(): Buffer {
    if (process.platform !== 'win32') {
      throw new Error('unsupported-platform');
    }
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    const ns = require('node-screenshots') as { Monitor: { all(): Array<any> } };
    const monitors = ns.Monitor.all();
    if (monitors.length === 0) {
      throw new Error('no-monitor');
    }
    const image = monitors[0].captureImageSync();
    return image.toPngSync() as Buffer;
  }
}
