using Health.Application.Medications;

namespace Health.Infrastructure.AI.AgentHandlers;

/// <summary>
/// 药管家 Agent 工具处理器。
/// </summary>
public static class MedicationAgentHandler
{
    public static readonly ToolDefinition ManageMedicationTool = new()
    {
        Function = new()
        {
            Name = "manage_medication",
            Description = "用药管理（创建/查询/确认服药）",
            Parameters = new
            {
                type = "object",
                properties = new
                {
                    action = new { type = "string", description = "create/query/confirm" },
                    medication_id = new { type = "string", description = "药品 ID，确认服药时使用" },
                    name = new { type = "string", description = "药品名称" },
                    dosage = new { type = "string", description = "剂量，如 100mg" },
                    frequency = new { type = "string", description = "频率，如 Daily/EveryOtherDay/Weekly" },
                    time_of_day = new { type = "array", items = new { type = "string" }, description = "服药时间，如 [\"08:00\",\"20:00\"]" },
                    duration_days = new { type = "integer", description = "服用天数" },
                    start_date = new { type = "string", description = "开始日期 yyyy-MM-dd" },
                },
                required = new[] { "action" }
            }
        }
    };

    public static List<ToolDefinition> Tools => [ManageMedicationTool, CommonAgentHandler.CheckArchiveTool];
    public static async Task<object> Execute(
        string toolName,
        JsonElement args,
        Guid userId,
        IMedicationService medications,
        CancellationToken ct = default)
    {
        return toolName switch
        {
            "manage_medication" => await ExecuteManageMedication(medications, userId, args, ct),
            _ => new { success = false, message = $"未知工具: {toolName}" }
        };
    }

    private static async Task<object> ExecuteManageMedication(IMedicationService medications, Guid userId, JsonElement args, CancellationToken ct)
    {
        var action = args.TryGetProperty("action", out var a) ? a.GetString()! : "query";
        return action switch
        {
            "create" => await CreateMedication(medications, userId, args, ct),
            "query" => await QueryMedications(medications, userId, ct),
            "confirm" => await ConfirmMedication(medications, userId, args, ct),
            _ => new { success = false, message = $"未知操作: {action}" }
        };
    }

    private static async Task<object> CreateMedication(IMedicationService medications, Guid userId, JsonElement args, CancellationToken ct)
    {
        var name = args.TryGetProperty("name", out var n) ? n.GetString()! : "";
        var dosage = args.TryGetProperty("dosage", out var dg) ? dg.GetString() : null;
        var frequency = ReadFrequency(args);
        var times = ReadTimes(args);
        var durationDays = args.TryGetProperty("duration_days", out var dd) ? dd.GetInt32() : 0;
        var startDate = ReadStartDate(args);
        // 结束日为包含式（IsActiveOn 用 EndDate >= date 判断），故 N 天疗程结束日 = 起始日 + (N-1)
        var endDate = durationDays > 0 ? startDate.AddDays(durationDays - 1) : (DateOnly?)null;

        var medicationId = await medications.CreateAsync(userId, new MedicationUpsertRequest(
            name,
            dosage,
            frequency,
            times.Count > 0 ? times : [new TimeOnly(8, 0)],
            startDate,
            endDate,
            MedicationSource.AiEntry,
            null), ct);

        var timeLabels = times.Count > 0 ? string.Join(", ", times.Select(t => t.ToString("HH:mm"))) : "08:00";
        return new
        {
            success = true,
            medication_id = medicationId,
            name,
            dosage,
            frequency = frequency.ToString(),
            time = timeLabels,
            start_date = startDate.ToString("yyyy-MM-dd"),
            duration_days = durationDays,
        };
    }

    private static async Task<object> QueryMedications(IMedicationService medications, Guid userId, CancellationToken ct)
    {
        var meds = await medications.ListActiveAsync(userId, ct);
        return new { count = meds.Count, medications = meds.Select(m => new { m.Id, m.Name, m.Dosage, m.TimeOfDay }) };
    }

    private static async Task<object> ConfirmMedication(IMedicationService medications, Guid userId, JsonElement args, CancellationToken ct)
    {
        var medId = args.TryGetProperty("medication_id", out var mid) ? mid.GetGuid() : Guid.Empty;
        var success = await medications.ConfirmNowAsync(userId, medId, ct);
        return success ? new { success = true } : new { success = false, message = "药品不存在或今天已经打卡" };
    }


    private static MedicationFrequency ReadFrequency(JsonElement args)
    {
        var frequencyStr = args.TryGetProperty("frequency", out var f) ? f.GetString() : "Daily";
        return Enum.TryParse<MedicationFrequency>(frequencyStr, out var frequency) ? frequency : MedicationFrequency.Daily;
    }

    private static DateOnly ReadStartDate(JsonElement args)
    {
        var startDateStr = args.TryGetProperty("start_date", out var sd) && sd.GetString() is string sds ? sds : null;
        return DateOnly.TryParse(startDateStr, out var parsedDate)
            ? parsedDate
            : DateOnly.FromDateTime(DateTime.UtcNow.AddHours(8));
    }

    private static List<TimeOnly> ReadTimes(JsonElement args)
    {
        List<TimeOnly> times = [];
        if (!args.TryGetProperty("time_of_day", out var tod) || tod.ValueKind != JsonValueKind.Array)
            return times;

        foreach (var t in tod.EnumerateArray())
        {
            if (TimeOnly.TryParse(t.GetString(), out var parsed)) times.Add(parsed);
        }

        return times;
    }
}
