using Health.Application.Diets;
using Health.Infrastructure.AI;

namespace Health.Infrastructure.Diets;

public sealed class DietImageAnalyzer(VisionClient vision) : IDietImageAnalyzer
{
    private readonly VisionClient _vision = vision;

    public async Task<DietImageAnalysisResult> AnalyzeAsync(DietImageAnalysisJob job, CancellationToken ct)
    {
        var imageUrls = new List<string>();
        foreach (var filePath in job.FilePaths)
        {
            if (!File.Exists(filePath))
                return new DietImageAnalysisResult(false, 40004, null, "待识别图片不存在");

            var bytes = await File.ReadAllBytesAsync(filePath, ct);
            var base64 = Convert.ToBase64String(bytes);
            if (base64.Length > 7 * 1024 * 1024)
                return new DietImageAnalysisResult(false, 40001, null, "图片过大，请压缩后重新上传");

            var extension = Path.GetExtension(filePath).ToLowerInvariant();
            var mime = extension switch
            {
                ".png" => "image/png",
                ".heic" => "image/heic",
                _ => "image/jpeg"
            };
            imageUrls.Add($"data:{mime};base64,{base64}");
        }

        var prompt = """
            你是营养师助手。请识别图片中所有食物和饮品，估算每项的具体克数或毫升数，输出 JSON 数组。

            ## 无食物判定（必读）
            如果图片中完全没有可食用的食物或饮品（例如是风景、人物、宠物、文档、屏幕截图、纯背景、空盘子等），**直接输出空数组 []**，不要硬编造食物。

            ## 输出格式
            [{"name":"食物名","portion":"具体克数","calories":数字}]

            ## 份量估算依据（容器与参照物对照表）
            - 标准饭碗(口径11cm)：满碗米饭≈200g、满碗面条≈250g、满碗粥≈250g、半碗≈100g
            - 标准汤碗(口径14cm)：满碗汤≈400ml、半碗≈200ml
            - 标准盘子(口径23cm)：满盘菜≈300g、半盘≈150g
            - 普通玻璃杯：满杯水/饮料≈250ml、纸杯≈200ml
            - 鸡蛋1个≈50g、馒头1个≈100g、包子1个≈80g、饺子1个≈15g
            - 香蕉1根≈100g、苹果1个≈200g、橘子1个≈120g
            - 肉块巴掌大小≈80-120g、鸡腿1个≈100g、鱼1条(中等)≈300g

            ## 输出示例（务必模仿此风格）
            正确：{"name":"米饭","portion":"约200g","calories":230}
            正确：{"name":"红烧肉","portion":"约150g","calories":420}
            正确：{"name":"豆浆","portion":"约250ml","calories":80}
            错误：{"name":"米饭","portion":"一碗","calories":230}        ← portion 缺克数
            错误：{"name":"汤","portion":"一份","calories":80}           ← portion 缺毫升数
            错误：{"name":"水果","portion":"少许","calories":50}         ← portion 是模糊词

            ## 硬性要求
            1. 图片若无食物，输出 [] 即可。不要硬凑食物。
            2. portion 字段必须包含阿拉伯数字 + 单位(g 或 ml)。不允许任何只有量词没有克数的回答。
            3. 即使图片不够清楚，也要根据可见容器/参照物给出估算，可加"约"或区间("约80-120g")。
            4. calories 是数字（千卡），不带单位、不带引号。

            只输出 JSON 数组本身，不要任何前缀、后缀、代码块标记或说明文字。
            """;
        var response = await _vision.VisionAsync(prompt, imageUrls, userText: null, maxTokens: 8192, ct: ct);
        var result = response.Choices?.FirstOrDefault()?.Message?.Content ?? "[]";
        return new DietImageAnalysisResult(true, 0, result, null);
    }
}
