{
  "openapi": "3.0.3",
  "info": {
    "title": "看雪山 · 日照金山预报 API",
    "version": "1.0.0",
    "description": "中国 79 座雪山的日照金山时段预报、观景点与多因素天气评分。数据服务地址 http://81.70.177.200:3000（本文件仅供接口发现，实际调用请使用 3000 端口）。"
  },
  "servers": [
    { "url": "http://81.70.177.200:3000" }
  ],
  "paths": {
    "/api/peaks": {
      "get": {
        "summary": "按观景点经纬度查询周边雪山及日照金山预报",
        "description": "返回可见雪山列表，含日出/日落金山时段（本地时间 HH:MM）、0-100 多因素评分（云量/降水/湿度/风）、云量湿度风等天气因子、中文提示。",
        "parameters": [
          { "name": "lat", "in": "query", "required": true, "schema": { "type": "number" }, "description": "观景点纬度（WGS-84）" },
          { "name": "lng", "in": "query", "required": true, "schema": { "type": "number" }, "description": "观景点经度（WGS-84）" },
          { "name": "date", "in": "query", "required": false, "schema": { "type": "string", "format": "date" }, "description": "查询日期 YYYY-MM-DD，缺省今天；天气预报仅支持未来 7 天" },
          { "name": "radius", "in": "query", "required": false, "schema": { "type": "number", "default": 100 }, "description": "查询半径（公里）" }
        ],
        "responses": {
          "200": {
            "description": "查询结果",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "location": { "type": "object", "properties": { "lat": { "type": "number" }, "lng": { "type": "number" }, "name": { "type": "string" }, "alt": { "type": "number" } } },
                    "date": { "type": "string" },
                    "peaks": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": { "type": "string", "description": "山峰中文名" },
                          "elevation": { "type": "integer", "description": "海拔（米）" },
                          "distance_km": { "type": "number" },
                          "visible": { "type": "boolean", "description": "是否可见（DEM 视域判断）" },
                          "golden_morning": { "type": "object", "nullable": true, "properties": { "start": { "type": "string" }, "end": { "type": "string" }, "duration_min": { "type": "integer" } }, "description": "日出金山时段，无则 null" },
                          "golden_evening": { "type": "object", "nullable": true, "properties": { "start": { "type": "string" }, "end": { "type": "string" }, "duration_min": { "type": "integer" } }, "description": "日落金山时段，无则 null" },
                          "cloud_cover_pct": { "type": "number", "description": "金光窗口小时云量 %" },
                          "visibility_rating": { "type": "string", "enum": ["优", "良", "差", "不可用"] },
                          "visibility_score": { "type": "integer", "description": "0-100 综合评分（-1=天气数据不可用）" },
                          "visibility_tip": { "type": "string", "description": "中文提示（影响可见性的主要因素）" },
                          "visibility_factors": { "type": "object", "properties": { "cloud": { "type": "number" }, "low_cloud": { "type": "number" }, "precip": { "type": "number" }, "humidity": { "type": "number" }, "temp": { "type": "number" }, "wind": { "type": "number" }, "wind_dir": { "type": "number" } } }
                        }
                      }
                    },
                    "meta": { "type": "object", "properties": { "total_peaks_in_range": { "type": "integer" }, "visible_peaks": { "type": "integer" }, "dem_available": { "type": "boolean" }, "weather_available": { "type": "boolean" } } }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/search": {
      "get": {
        "summary": "按名称搜索山峰，返回山峰信息与推荐观景点",
        "parameters": [
          { "name": "q", "in": "query", "required": true, "schema": { "type": "string" }, "description": "山峰名关键词（支持中文/英文/子序列，如 贡嘎、卡瓦格博、K2）" }
        ],
        "responses": {
          "200": {
            "description": "匹配的山峰列表",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "matches": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name_zh": { "type": "string" },
                          "name_en": { "type": "string" },
                          "lat": { "type": "number" },
                          "lng": { "type": "number" },
                          "elevation": { "type": "integer" },
                          "viewpoints": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "name": { "type": "string", "description": "观景点名（子梅垭口、飞来寺、台怀镇等）" },
                                "lat": { "type": "number" },
                                "lng": { "type": "number" },
                                "desc": { "type": "string" },
                                "heading_offset": { "type": "number" }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "summary": "健康检查",
        "responses": { "200": { "description": "服务正常", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string" } } } } } } }
      }
    },
    "/api/dem-coverage": {
      "get": {
        "summary": "已加载 DEM 地形瓦片覆盖范围",
        "responses": { "200": { "description": "瓦片范围列表", "content": { "application/json": { "schema": { "type": "object", "properties": { "tiles": { "type": "array", "items": { "type": "object", "properties": { "lat_min": { "type": "number" }, "lat_max": { "type": "number" }, "lng_min": { "type": "number" }, "lng_max": { "type": "number" } } } } } } } } } }
      }
    },
    "/api/view-height": {
      "get": {
        "summary": "3D 相机高度：从观景点看目标峰的最小相机高度",
        "parameters": [
          { "name": "lat", "in": "query", "required": true, "schema": { "type": "number" } },
          { "name": "lng", "in": "query", "required": true, "schema": { "type": "number" } },
          { "name": "tlat", "in": "query", "required": true, "schema": { "type": "number" }, "description": "目标峰纬度" },
          { "name": "tlng", "in": "query", "required": true, "schema": { "type": "number" }, "description": "目标峰经度" }
        ],
        "responses": { "200": { "description": "相机高度", "content": { "application/json": { "schema": { "type": "object", "properties": { "height": { "type": "number" }, "base": { "type": "number" }, "target": { "type": "number" } } } } } } }
      }
    },
    "/api/elev": {
      "get": {
        "summary": "单点 DEM 海拔",
        "parameters": [
          { "name": "lat", "in": "query", "required": true, "schema": { "type": "number" } },
          { "name": "lng", "in": "query", "required": true, "schema": { "type": "number" } }
        ],
        "responses": { "200": { "description": "海拔（米），无 DEM 数据时 height 为 null", "content": { "application/json": { "schema": { "type": "object", "properties": { "height": { "type": "number", "nullable": true } } } } } } }
      }
    },
    "/api/stats": {
      "get": {
        "summary": "接口调用统计",
        "description": "按接口/来源客户端/地区/IP 的调用计数（内存计数，进程重启清零）",
        "responses": { "200": { "description": "统计快照", "content": { "application/json": { "schema": { "type": "object", "properties": { "total": { "type": "integer" }, "endpoints": { "type": "object" }, "by_client": { "type": "object" }, "by_region": { "type": "object" }, "by_ip": { "type": "object" }, "bots": { "type": "object" } } } } } } }
      }
    },
    "/api/terrain/layer.json": {
      "get": {
        "summary": "Cesium TerrainProvider 元数据",
        "description": "3D 地形源的 tilejson 元数据（heightmap-1.0）",
        "responses": { "200": { "description": "tilejson 元数据", "content": { "application/json": { "schema": { "type": "object" } } } } }
      }
    },
    "/api/terrain/:z/:x/:y": {
      "get": {
        "summary": "Cesium heightmap-1.0 地形瓦片",
        "parameters": [
          { "name": "z", "in": "path", "required": true, "schema": { "type": "integer" } },
          { "name": "x", "in": "path", "required": true, "schema": { "type": "integer" } },
          { "name": "y", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": { "200": { "description": "地形瓦片字节流", "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } } }
      }
    },
    "/api/cams": {
      "get": {
        "summary": "雪山实况直播源列表",
        "description": "返回可用 24h 慢直播源（云南广电七彩云端官方 HLS）。播放列表经 /api/cams/m3u8/:id 代理，段文件经 /api/cams/seg/:id/:file 代理（上游证书过期+CORS 问题已由代理规避）。",
        "responses": { "200": { "description": "直播源列表", "content": { "application/json": { "schema": { "type": "object", "properties": { "cams": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "viewpoint": { "type": "string" }, "name": { "type": "string" }, "platform": { "type": "string" }, "src": { "type": "string" }, "page": { "type": "string" }, "stars": { "type": "string" } } } } } } } } } }
      }
    },
    "/api/cams/m3u8/:id": {
      "get": {
        "summary": "代理直播源 HLS 播放列表",
        "description": "拉取上游 m3u8 并把相对 .ts/.m3u8 地址改写为本地 /api/cams/seg/:id/:file 代理地址，供 hls.js/原生播放器使用。",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "直播源 id（如 feilai-meili）" }
        ],
        "responses": {
          "200": { "description": "m3u8 播放列表", "content": { "application/vnd.apple.mpegurl": { "schema": { "type": "string" } } } },
          "404": { "description": "未知直播源 id" },
          "502": { "description": "上游拉流失败/返回错误" }
        }
      }
    },
    "/api/cams/seg/:id/:file": {
      "get": {
        "summary": "代理直播 TS 段文件",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "file", "in": "path", "required": true, "schema": { "type": "string" }, "description": "段文件名（仅字母数字._-，防路径穿越）" }
        ],
        "responses": {
          "200": { "description": "TS 段字节流", "content": { "video/mp2t": { "schema": { "type": "string", "format": "binary" } } } },
          "404": { "description": "未知直播源" },
          "502": { "description": "上游取段失败" }
        }
      }
    },
    "/api/camsnap/:cam": {
      "get": {
        "summary": "快照回放列表",
        "description": "返回该直播源最近 42 张快照（约 7 天，按时间倒序）。快照文件可直接访问 {web}/camsnap/:cam/:file。",
        "parameters": [ { "name": "cam", "in": "path", "required": true, "schema": { "type": "string" } } ],
        "responses": { "200": { "description": "快照列表", "content": { "application/json": { "schema": { "type": "object", "properties": { "cam": { "type": "string" }, "snaps": { "type": "array", "items": { "type": "object", "properties": { "file": { "type": "string" }, "ts": { "type": "integer" } } } } } } } } } }
      },
      "post": {
        "summary": "保存快照（前端 canvas 截图）",
        "description": "请求体为原生 JPEG 字节（canvas.toBlob，2MB 上限）。服务端仅保存 JPEG（魔数校验），每路最多 200 张，超出删最旧。",
        "parameters": [ { "name": "cam", "in": "path", "required": true, "schema": { "type": "string" } } ],
        "requestBody": { "content": { "image/jpeg": { "schema": { "type": "string", "format": "binary" } } } },
        "responses": {
          "200": { "description": "保存成功", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "file": { "type": "string" }, "url": { "type": "string" } } } } } },
          "400": { "description": "非 JPEG / 超限 / 为空" },
          "404": { "description": "未知直播源" }
        }
      }
    }
  }
}
