package routes

import (
	"github.com/gofiber/fiber/v2"

	openapiHandler "github.com/break/junhong_cmp_fiber/internal/handler/openapi"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"github.com/break/junhong_cmp_fiber/pkg/openapi"
)

// RegisterOpenAPIRoutes 注册代理开放接口路由
func RegisterOpenAPIRoutes(router fiber.Router, handler *openapiHandler.Handler, doc *openapi.Generator, basePath string) {
	const tag = "代理开放接口"
	const authDescription = `认证方式：
1. 每个请求必须携带 Header：X-Agent-Account、X-Agent-Password、X-Agent-Timestamp、X-Agent-Nonce、X-Agent-Sign。
2. Header 字段说明：
   - X-Agent-Account：代理账号标识，填写代理登录平台使用的用户名或手机号，例如 agent001；该值由平台开通代理账号时提供，必须与签名原文 account 行完全一致。
   - X-Agent-Password：代理账号当前登录密码，由代理账号持有人提供；该值同时作为 HMAC-SHA256 签名密钥，密码变更后必须使用新密码签名。
   - X-Agent-Timestamp：请求发起时间，由调用方生成，支持 Unix 秒、Unix 毫秒或 RFC3339 时间，例如 1715400000、1715400000000 或 2024-05-11T10:00:00+08:00；必须与签名原文 timestamp 行完全一致。
   - X-Agent-Nonce：请求随机串，由调用方每次请求自行生成，例如 UUID、雪花 ID 或“时间戳+随机数”；不需要平台提前分配，同一账号在 5 分钟内不可重复。
   - X-Agent-Sign：请求签名，由调用方按下方规则实时计算得到，不是平台分配的固定值；只要 method、path、query、body、timestamp、nonce、account 或 password 任意一个变化，签名都会变化。
3. X-Agent-Timestamp 超出允许时间窗口会认证失败；客户端服务器时间应保持同步。
4. X-Agent-Nonce 重复会被判定为重放请求。
5. 签名原文按 7 行拼接，行尾使用 \n，最后一行后不追加换行：
METHOD
PATH
canonical_query
body_sha256
timestamp
nonce
account
6. METHOD 使用大写 HTTP 方法；PATH 只取请求路径，例如 /api/open/v1/cards/status，不包含域名和 query。
7. canonical_query 为 query 参数规范化结果：排除 sign 字段，参数名升序；同名多值按值升序；key 和 value 使用 URL QueryEscape 编码后用 key=value 拼接，多个参数用 & 连接；无 query 时为空字符串。
8. body_sha256 为原始请求 body 字节的 SHA256 小写十六进制值；GET 或空 body 使用空字符串的 SHA256；POST JSON 请求必须用最终发送的 body 字符串计算，签名和请求发送的 body 必须完全一致。
9. X-Agent-Sign = hex(HMAC-SHA256(password, sign_payload))，password 为 X-Agent-Password 的原始值，结果使用小写十六进制。

Node.js 签名示例：

` + "```javascript\n" + `const crypto = require("crypto");

function queryEscape(value) {
  return new URLSearchParams({ v: String(value) }).toString().slice(2);
}

function canonicalQuery(params) {
  return Object.entries(params || {})
    .filter(([key]) => key.toLowerCase() !== "sign")
    .flatMap(([key, value]) => {
      const values = Array.isArray(value) ? value : [value];
      return values.sort().map((item) => [key, item]);
    })
    .sort(([aKey, aValue], [bKey, bValue]) => {
      if (aKey === bKey) return String(aValue).localeCompare(String(bValue));
      return aKey.localeCompare(bKey);
    })
    .map(([key, value]) => queryEscape(key) + "=" + queryEscape(value))
    .join("&");
}

function buildAgentSign({ method, path, query, body, timestamp, nonce, account, password }) {
  const bodyText = body || "";
  const bodyHash = crypto.createHash("sha256").update(bodyText).digest("hex");
  const signPayload = [
    method.toUpperCase(),
    path,
    canonicalQuery(query),
    bodyHash,
    timestamp,
    nonce,
    account,
  ].join("\n");
  return crypto.createHmac("sha256", password).update(signPayload).digest("hex");
}
` + "```"

	Register(router, doc, basePath, "GET", "/cards/traffic", handler.GetCardTraffic, RouteSpec{
		Summary:        "查询单卡或设备流量",
		Description:    authDescription + "\n\n按 card_no 查询流量、当前套餐和待生效套餐。card_no 支持三种解析路径：1) ICCID/虚拟号/MSISDN 对应独立卡，查卡维度流量；2) 已绑定设备的卡，自动反查绑定设备，查设备维度流量（响应含 device_no）；3) IMEI 或设备虚拟号，直接查设备维度流量（响应含 device_no）。",
		Input:          new(dto.AgentOpenAPICardQueryRequest),
		Output:         new(dto.AgentOpenAPICardTrafficResponse),
		Tags:           []string{tag},
		Auth:           true,
		SecurityScheme: openapi.SecuritySchemeAgentOpenAPI,
	})
	Register(router, doc, basePath, "GET", "/cards/status", handler.GetCardStatus, RouteSpec{
		Summary:        "查询单卡状态",
		Description:    authDescription + "\n\n按 card_no 查询单卡状态，返回正常或停机以及停机原因。",
		Input:          new(dto.AgentOpenAPICardQueryRequest),
		Output:         new(dto.AgentOpenAPICardStatusResponse),
		Tags:           []string{tag},
		Auth:           true,
		SecurityScheme: openapi.SecuritySchemeAgentOpenAPI,
	})
	Register(router, doc, basePath, "GET", "/cards/realname-status", handler.GetRealnameStatus, RouteSpec{
		Summary:        "查询单卡实名状态",
		Description:    authDescription + "\n\n按 card_no 查询单卡实名状态。",
		Input:          new(dto.AgentOpenAPICardQueryRequest),
		Output:         new(dto.AgentOpenAPIRealnameStatusResponse),
		Tags:           []string{tag},
		Auth:           true,
		SecurityScheme: openapi.SecuritySchemeAgentOpenAPI,
	})
	Register(router, doc, basePath, "POST", "/cards/resume", handler.ResumeCard, RouteSpec{
		Summary:        "机卡分离卡复机",
		Description:    authDescription + "\n\n按 card_no 调用上游复机接口。调用前检查本地落库的 Gateway 卡状态扩展字段，仅当 gateway_extend 等于“机卡分离停机”时允许复机，否则返回“仅允许机卡分离状态下的卡复机”。",
		Input:          new(dto.AgentOpenAPICardResumeRequest),
		Output:         new(dto.AgentOpenAPICardResumeResponse),
		Tags:           []string{tag},
		Auth:           true,
		SecurityScheme: openapi.SecuritySchemeAgentOpenAPI,
	})
	Register(router, doc, basePath, "GET", "/packages", handler.ListPackages, RouteSpec{
		Summary:        "查询套餐列表",
		Description:    authDescription + "\n\n分页查询当前账号可购买的套餐，返回套餐基础信息和价格。",
		Input:          new(dto.AgentOpenAPIPackageListRequest),
		Output:         new(dto.AgentOpenAPIPackageItem),
		Tags:           []string{tag},
		Auth:           true,
		SecurityScheme: openapi.SecuritySchemeAgentOpenAPI,
	})
	Register(router, doc, basePath, "POST", "/wallet/package-orders", handler.CreateWalletPackageOrders, RouteSpec{
		Summary:        "钱包套餐购买",
		Description:    authDescription + "\n\n使用预充值钱包为多张卡购买同一个套餐编码。每张卡独立下单，允许部分成功。",
		Input:          new(dto.AgentOpenAPIWalletPackageOrderRequest),
		Output:         new(dto.AgentOpenAPIWalletPackageOrderResponse),
		Tags:           []string{tag},
		Auth:           true,
		SecurityScheme: openapi.SecuritySchemeAgentOpenAPI,
	})
	Register(router, doc, basePath, "GET", "/wallet/balance", handler.GetWalletBalance, RouteSpec{
		Summary:        "查询预充值钱包余额",
		Description:    authDescription + "\n\n查询当前账号预充值钱包余额。未开通钱包时返回 0。",
		Output:         new(dto.AgentOpenAPIWalletBalanceResponse),
		Tags:           []string{tag},
		Auth:           true,
		SecurityScheme: openapi.SecuritySchemeAgentOpenAPI,
	})
	Register(router, doc, basePath, "GET", "/wallet/transactions", handler.ListWalletTransactions, RouteSpec{
		Summary:        "查询预充值钱包流水",
		Description:    authDescription + "\n\n分页查询当前账号预充值钱包流水。",
		Input:          new(dto.AgentOpenAPIWalletTransactionListRequest),
		Output:         new(dto.MainWalletTransactionItem),
		Tags:           []string{tag},
		Auth:           true,
		SecurityScheme: openapi.SecuritySchemeAgentOpenAPI,
	})
	Register(router, doc, basePath, "GET", "/devices/traffic", handler.GetDeviceTraffic, RouteSpec{
		Summary:        "查询设备套餐内流量",
		Description:    authDescription + "\n\n按 device_no 查询设备套餐内流量、当前套餐和待生效套餐。device_no 支持虚拟号、IMEI。",
		Input:          new(dto.AgentOpenAPIDeviceQueryRequest),
		Output:         new(dto.AgentOpenAPIDeviceTrafficResponse),
		Tags:           []string{tag},
		Auth:           true,
		SecurityScheme: openapi.SecuritySchemeAgentOpenAPI,
	})
	Register(router, doc, basePath, "POST", "/devices/switch-card", handler.SwitchDeviceCard, RouteSpec{
		Summary:        "切网（多卡设备切换 ICCID）",
		Description:    authDescription + "\n\n按 device_no 将多卡设备切换到指定 ICCID 的卡。",
		Input:          new(dto.AgentOpenAPIDeviceSwitchCardRequest),
		Tags:           []string{tag},
		Auth:           true,
		SecurityScheme: openapi.SecuritySchemeAgentOpenAPI,
	})
	Register(router, doc, basePath, "POST", "/devices/reboot", handler.RebootDevice, RouteSpec{
		Summary:        "重启设备",
		Description:    authDescription + "\n\n按 device_no 远程重启设备。",
		Input:          new(dto.AgentOpenAPIDeviceOperationRequest),
		Tags:           []string{tag},
		Auth:           true,
		SecurityScheme: openapi.SecuritySchemeAgentOpenAPI,
	})
	Register(router, doc, basePath, "POST", "/devices/reset", handler.ResetDevice, RouteSpec{
		Summary:        "恢复出厂设置",
		Description:    authDescription + "\n\n按 device_no 远程恢复设备出厂设置。",
		Input:          new(dto.AgentOpenAPIDeviceOperationRequest),
		Tags:           []string{tag},
		Auth:           true,
		SecurityScheme: openapi.SecuritySchemeAgentOpenAPI,
	})
}
