//! DeepSeek usage feed implementation.
//!
//! Mirrors prime-agent:packages/ai/src/utils/usage/providers/deepseek.ts field for field.
const std = @import("std");
const usage = @import("../usage.zig");

pub const DEEPSEEK_USAGE_URL = "https://api.deepseek.com/user/balance";

pub const ParseDeepSeekResult = struct {
    planType: ?[]const u8 = null,
    limits: []const usage.UsageLimit = &[_]usage.UsageLimit{},
    balance: ?[]const u8 = null,
    notes: []const []const u8 = &[_][]const u8{},
};

pub fn parseDeepSeekUsage(alloc: std.mem.Allocator, payload: ?std.json.Value) !ParseDeepSeekResult {
    const root = usage.asObject(payload);
    const infos = if (root) |r| usage.asArray(r.get("balance_infos")) else null;
    if (infos == null or infos.?.items.len == 0) return ParseDeepSeekResult{};

    const first = usage.asObject(infos.?.items[0]) orelse return ParseDeepSeekResult{};

    const total_val = first.get("total_balance");
    const total = if (usage.asString(total_val)) |s|
        s
    else if (usage.asNumber(total_val)) |n|
        try std.fmt.allocPrint(alloc, "{d:.2}", .{n})
    else
        "0.00";

    const curr_raw = usage.asString(first.get("currency")) orelse "USD";
    const currency = blk: {
        const trimmed = std.mem.trim(u8, curr_raw, " \t\r\n");
        if (trimmed.len == 0) break :blk "USD";
        const upper = try alloc.alloc(u8, trimmed.len);
        break :blk std.ascii.upperString(upper, trimmed);
    };

    const symbol = if (std.mem.eql(u8, currency, "CNY")) "¥" else "$";
    const balance = try std.fmt.allocPrint(alloc, "{s}{s} {s}", .{ symbol, total, currency });

    var notes = std.ArrayList([]const u8).empty;
    const is_available = if (root) |r| r.get("is_available") else null;
    if (is_available) |ia| {
        switch (ia) {
            .bool => |b| if (!b) try notes.append(alloc, "Account is unavailable"),
            else => {},
        }
    }

    return ParseDeepSeekResult{
        .planType = "Pay-as-you-go",
        .limits = &[_]usage.UsageLimit{},
        .balance = balance,
        .notes = notes.items,
    };
}

pub fn advance(
    alloc: std.mem.Allocator,
    credential_json: []const u8,
    responses_json: []const u8,
    _now_ms: i64,
) !usage.Outcome {
    _ = _now_ms;
    const cred_parsed = std.json.parseFromSlice(std.json.Value, alloc, credential_json, .{}) catch {
        return .{ .report = .{ .error_message = "invalid credential JSON" } };
    };
    const cred_root = usage.asObject(cred_parsed.value) orelse {
        return .{ .report = .{ .error_message = "invalid credential JSON" } };
    };
    const kind = usage.asString(cred_root.get("kind")) orelse "";
    if (!std.mem.eql(u8, kind, "apiKey")) {
        return .{ .report = .{ .error_message = "deepseek needs an apiKey credential" } };
    }

    const api_key = usage.asString(cred_root.get("apiKey")) orelse "";
    const cred_account_id = usage.asString(cred_root.get("accountId"));
    const cred_email = usage.asString(cred_root.get("email"));

    const resp_parsed = std.json.parseFromSlice(std.json.Value, alloc, responses_json, .{}) catch {
        return .{ .report = .{ .error_message = "invalid responses JSON" } };
    };
    const resp_array = usage.asArray(resp_parsed.value) orelse {
        return .{ .report = .{ .error_message = "invalid responses JSON" } };
    };

    if (resp_array.items.len == 0) {
        var headers = std.ArrayList([2][]const u8).empty;
        const auth_hdr = try std.fmt.allocPrint(alloc, "Bearer {s}", .{api_key});
        try headers.append(alloc, .{ "Authorization", auth_hdr });
        try headers.append(alloc, .{ "Accept", "application/json" });

        const requests = try alloc.alloc(usage.UsageRequest, 1);
        requests[0] = .{
            .method = "GET",
            .url = DEEPSEEK_USAGE_URL,
            .headers = headers.items,
        };
        return .{ .requests = requests };
    }

    const first = switch (try usage.parseFirstResponse(alloc, resp_array, "usage body is not JSON")) {
        .ok => |f| f,
        .err => |msg| return .{ .report = .{ .error_message = msg } },
    };
    const body_parsed = first.parsed;

    const parsed = try parseDeepSeekUsage(alloc, body_parsed.value);
    if (parsed.balance == null) {
        return .{ .report = .{ .error_message = "response missing balance_infos" } };
    }

    return .{
        .report = .{
            .planType = parsed.planType,
            .accountId = cred_account_id,
            .email = cred_email,
            .limits = parsed.limits,
            .balance = parsed.balance,
            .notes = parsed.notes,
            .error_message = null,
        },
    };
}
