const std = @import("std");
const config = @import("../config.zig");
const db = @import("../db.zig");
const core = @import("../core.zig");
const manifest_lib = @import("../manifest.zig");

/// Annotate command - unified metadata annotation
/// Usage:
///   ml annotate <run_id> --text "Try lr=3e-4 next"
///   ml annotate <run_id> --hypothesis "LR scaling helps"
///   ml annotate <run_id> --outcome validates --confidence 0.9
///   ml annotate <run_id> --privacy private
pub fn execute(allocator: std.mem.Allocator, args: []const []const u8) !void {
    var flags = core.flags.CommonFlags{};
    var command_args = try core.flags.parseCommon(allocator, args, &flags);
    defer command_args.deinit(allocator);

    core.output.setMode(if (flags.json) .json else .text);

    if (flags.help) {
        return printUsage();
    }

    if (command_args.items.len < 1) {
        std.log.err("Usage: ml annotate <run_id> [options]", .{});
        return error.MissingArgument;
    }

    const run_id = command_args.items[0];

    // Parse metadata options
    const text = core.flags.parseKVFlag(command_args.items, "text");
    const hypothesis = core.flags.parseKVFlag(command_args.items, "hypothesis");
    const outcome = core.flags.parseKVFlag(command_args.items, "outcome");
    const confidence = core.flags.parseKVFlag(command_args.items, "confidence");
    const privacy = core.flags.parseKVFlag(command_args.items, "privacy");
    const author = core.flags.parseKVFlag(command_args.items, "author");

    // Check that at least one option is provided
    if (text == null and hypothesis == null and outcome == null and privacy == null) {
        std.log.err("No metadata provided. Use --text, --hypothesis, --outcome, or --privacy", .{});
        return error.MissingMetadata;
    }

    const cfg = try config.Config.load(allocator);
    defer {
        var mut_cfg = cfg;
        mut_cfg.deinit(allocator);
    }

    // Get DB path
    const db_path = try cfg.getDBPath(allocator);
    defer allocator.free(db_path);

    var database = try db.DB.init(allocator, db_path);
    defer database.close();

    // Verify run exists
    const check_sql = "SELECT 1 FROM ml_runs WHERE run_id = ?;";
    const check_stmt = try database.prepare(check_sql);
    defer db.DB.finalize(check_stmt);
    try db.DB.bindText(check_stmt, 1, run_id);
    const has_row = try db.DB.step(check_stmt);
    if (!has_row) {
        std.log.err("Run not found: {s}", .{run_id});
        return error.RunNotFound;
    }

    // Add text note as a tag
    if (text) |t| {
        try addTag(allocator, &database, run_id, "note", t, author);
    }

    // Add hypothesis
    if (hypothesis) |h| {
        try addTag(allocator, &database, run_id, "hypothesis", h, author);
    }

    // Add outcome
    if (outcome) |o| {
        try addTag(allocator, &database, run_id, "outcome", o, author);
        if (confidence) |c| {
            try addTag(allocator, &database, run_id, "confidence", c, author);
        }
    }

    // Add privacy level
    if (privacy) |p| {
        try addTag(allocator, &database, run_id, "privacy", p, author);
    }

    // Checkpoint WAL
    database.checkpointOnExit();

    if (flags.json) {
        std.debug.print("{{\"success\":true,\"run_id\":\"{s}\",\"action\":\"note_added\"}}\n", .{run_id});
    } else {
        std.debug.print("Added note to run {s}\n", .{run_id[0..8]});
    }
}

fn addTag(
    allocator: std.mem.Allocator,
    database: *db.DB,
    run_id: []const u8,
    key: []const u8,
    value: []const u8,
    author: ?[]const u8,
) !void {
    const full_value = if (author) |a|
        try std.fmt.allocPrint(allocator, "{s} (by {s})", .{ value, a })
    else
        try allocator.dupe(u8, value);
    defer allocator.free(full_value);

    const sql = "INSERT INTO ml_tags (run_id, key, value) VALUES (?, ?, ?);";
    const stmt = try database.prepare(sql);
    defer db.DB.finalize(stmt);

    try db.DB.bindText(stmt, 1, run_id);
    try db.DB.bindText(stmt, 2, key);
    try db.DB.bindText(stmt, 3, full_value);
    _ = try db.DB.step(stmt);
}

fn printUsage() !void {
    std.debug.print("Usage: ml annotate <run_id> [options]\n\n", .{});
    std.debug.print("Add metadata annotations to a run.\n\n", .{});
    std.debug.print("Options:\n", .{});
    std.debug.print("\t--text <string>\t\tFree-form annotation\n", .{});
    std.debug.print("\t--hypothesis <string>\tResearch hypothesis\n", .{});
    std.debug.print("\t--outcome <status>\tOutcome: validates/refutes/inconclusive\n", .{});
    std.debug.print("\t--confidence <0-1>\tConfidence in outcome\n", .{});
    std.debug.print("\t--privacy <level>\tPrivacy: private/team/public\n", .{});
    std.debug.print("\t--author <name>\t\tAuthor of the annotation\n", .{});
    std.debug.print("\t--help, -h\t\tShow this help\n", .{});
    std.debug.print("\t--json\t\t\tOutput structured JSON\n\n", .{});
    std.debug.print("Examples:\n", .{});
    std.debug.print("\tml annotate abc123 --text \"Try lr=3e-4 next\"\n", .{});
    std.debug.print("\tml annotate abc123 --hypothesis \"LR scaling helps\"\n", .{});
    std.debug.print("\tml annotate abc123 --outcome validates --confidence 0.9\n", .{});
}
