import https from 'https';
import fs from 'fs';
import { execFileSync } from 'child_process';

// 本 action 會連接自架 Gitea / OpenCode，部署環境可能使用內部 CA 或自簽憑證。
// 對外部服務請優先使用預設 TLS 驗證；需要內部服務相容時才使用 getInsecureHttpsAgent()。
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

/**
 * 讀取 runner 寫入的事件 payload JSON（`GITHUB_EVENT_PATH` / `GITEA_EVENT_PATH`）。
 * 讀不到或解析失敗時回傳空物件，讓後續取值一律走 fallback，不讓 import 期噴錯。
 *
 * @returns {Record<string, any>} 事件 payload 物件，失敗時為 `{}`。
 */
function readEventPayload() {
  const eventPath = process.env.GITHUB_EVENT_PATH || process.env.GITEA_EVENT_PATH;
  if (!eventPath) return {};
  try {
    return JSON.parse(fs.readFileSync(eventPath, 'utf8'));
  } catch {
    return {};
  }
}

const EVENT = readEventPayload();
const PR = EVENT.pull_request || {};

// 取值優先序：有對應 `with:` 輸入的欄位一律 INPUT_* 優先（使用端明確傳入的值最權威，
// 蓋過環境中剛好存在的 ambient env）→ 專用 env（相容舊 Docker 版與測試）→ 內建預設。
// 無對應輸入的欄位（server url / repository / PR_*）則走專用 env → runner 內建 / 事件 payload。
// 使用端 workflow 只需傳 `with: token`。
export const GITEA_TOKEN = process.env.INPUT_TOKEN || process.env.GITEA_TOKEN || '';
export const GITEA_COMMENT_TOKEN = process.env.INPUT_COMMENT_TOKEN || process.env.GITEA_COMMENT_TOKEN || process.env.INPUT_TOKEN || process.env.GITEA_TOKEN || '';
export const GITEA_SERVER_URL = process.env.GITEA_SERVER_URL || process.env.GITHUB_SERVER_URL || 'https://gitea.com';
export const GITEA_REPOSITORY = process.env.GITEA_REPOSITORY || process.env.GITHUB_REPOSITORY || '';
export const PR_NUMBER = process.env.PR_NUMBER || (PR.number != null ? String(PR.number) : '');
export const PR_HEAD_SHA = process.env.PR_HEAD_SHA || PR.head?.sha || process.env.GITHUB_SHA || '';
export const PR_HEAD_BRANCH = process.env.PR_HEAD_BRANCH || PR.head?.ref || process.env.GITHUB_HEAD_REF || '';
export const PR_BASE_BRANCH = process.env.PR_BASE_BRANCH || PR.base?.ref || process.env.GITHUB_BASE_REF || '';

export const FINDINGS_PATH = '.gitea/ai-review/findings.json';
export const EXCLUSIONS_PATH = '.gitea/ai-review/exclusions.json';

/**
 * 建立一個停用 TLS 憑證驗證（`rejectUnauthorized: false`）的 HTTPS Agent，
 * 供連接使用自簽或無效憑證的內部服務時使用。
 *
 * @remarks 首次呼叫時建立，之後快取為模組層級單例（singleton）重複使用，
 *          避免每次都新建 Agent 與連線池、浪費 TCP 三次握手。
 *          停用憑證驗證有中間人攻擊風險，僅限受信任的內部環境使用。
 * @returns {import('https').Agent} 已關閉憑證驗證的 HTTPS Agent 單例。
 */
let _insecureHttpsAgent = null;
/**
 * 取得一個關閉 TLS 憑證驗證的 HTTPS Agent 單例，供內部服務連線使用。
 *
 * @remarks 只應在信任的內網或測試環境使用；若需要完整 TLS 安全性，應改用預設
 *          `https.Agent`，不要調用這個函式。
 */
export function getInsecureHttpsAgent() {
  return (_insecureHttpsAgent ??= new https.Agent({ rejectUnauthorized: false }));
}

// 過渡別名：既有呼叫端仍可用 OpenCode 語意名稱；新程式碼請直接使用 getInsecureHttpsAgent。
export const getOpenCodeHttpsAgent = getInsecureHttpsAgent;

const CLI_CANDIDATES = [
  {
    provider: 'codex',
    command: 'codex',
    defaultModel: 'gpt-5.4-mini',
  },
  {
    provider: 'claude',
    command: 'claude',
    defaultModel: 'sonnet',
  },
  {
    provider: 'antigravity',
    command: 'agy',
    defaultModel: 'gemini-2.5-flash',
  },
  {
    provider: 'antigravity',
    command: 'antigravity',
    defaultModel: 'gemini-2.5-flash',
  },
  {
    provider: 'opencode',
    command: 'opencode',
    defaultModel: 'google/gemini-2.5-flash',
  },
];

/**
 * 取得目前支援的 LLM CLI 指令名稱清單。
 *
 * @remarks 內容直接取自 `CLI_CANDIDATES`，若日後候選清單增減，輸出會同步變動。
 */
export function getLLMCLICommands() {
  return CLI_CANDIDATES.map(c => c.command);
}

/**
 * 檢查指定 CLI 指令是否可在目前環境中執行。
 *
 * @param {string} command - 要檢查的指令名稱。
 * @returns {boolean} 找得到指令時回傳 `true`，否則回傳 `false`。
 * @remarks 透過 `/bin/sh -lc "command -v <command>"` 檢查，屬於同步存在性檢查。
 */
function commandExists(command) {
  try {
    execFileSync('/bin/sh', ['-lc', `command -v ${command}`], { stdio: 'ignore' });
    return true;
  } catch {
    return false;
  }
}

/**
 * 依環境變數解析並回傳 LLM 提供者設定。
 *
 * 優先使用 `AI_ASSISTANT_CLI` 指定的 CLI；未指定時依序偵測 codex、claude、antigravity、opencode。
 * model 依序取 `with: model`（`INPUT_MODEL`）、`MODEL`、相容舊的 `OPENCODE_MODEL`，最後用各 CLI 預設值。
 *
 * @param {{ commandExistsFn?: (command: string) => boolean }} [deps] - 可注入的 CLI 偵測函式，供測試使用。
 * @returns {{ provider: ('codex'|'claude'|'antigravity'|'opencode'|null), apiKeys: string[], baseURL: null, model: (string|null), command: (string|null) }}
 *          LLM 設定物件；`provider` 為 `null` 表示沒有可用的提供者。
 */
export function getLLMConfig({ commandExistsFn = commandExists } = {}) {
  const requested = process.env.AI_ASSISTANT_CLI;
  const candidates = requested
    ? CLI_CANDIDATES.filter(c => c.provider === requested || c.command === requested)
    : CLI_CANDIDATES;
  const cli = candidates.find(c => commandExistsFn(c.command));
  if (!cli) return { provider: null, apiKeys: [], baseURL: null, model: null, command: null };

  return {
    provider: cli.provider,
    apiKeys: [cli.provider],
    baseURL: null,
    model: process.env.INPUT_MODEL || process.env.MODEL || process.env.OPENCODE_MODEL || cli.defaultModel,
    command: cli.command,
  };
}
