using System.Text.Json;
using System.Text.Json.Serialization;

using Microsoft.Teams.Apps.Activities;
using Microsoft.Teams.Apps.Activities.Invokes;
using Microsoft.Teams.Apps.Extensions;
using Microsoft.Teams.Common;
using Microsoft.Teams.Plugins.AspNetCore.Extensions;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
builder.AddTeams();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();
var teams = app.UseTeams();
app.AddTab("dialog-form", "Web/dialog-form");

teams.OnMessage(async (context, cancellationToken) =>
{
    var activity = context.Activity;
    context.Log.Info($"[MESSAGE] Received: {SanitizeForLog(activity.Text)}");
    context.Log.Info($"[MESSAGE] From: {SanitizeForLog(activity.From?.Name ?? "unknown")}");

    var card = CreateDialogLauncherCard();
    await context.Send(card, cancellationToken);
});

teams.OnTaskFetch((context, cancellationToken) =>
{
    var activity = context.Activity;
    context.Log.Info("[TASK_FETCH] Task fetch request received");

    var data = activity.Value?.Data as JsonElement?;
    if (data == null)
    {
        context.Log.Info("[TASK_FETCH] No data found in the activity value");
        return Task.FromResult(new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("No data found in the activity value")));
    }

    var dialogType = data.Value.TryGetProperty("dialog_id", out var dialogTypeElement) && dialogTypeElement.ValueKind == JsonValueKind.String
        ? dialogTypeElement.GetString()
        : null;

    context.Log.Info($"[TASK_FETCH] Dialog type: {dialogType}");

    var response = dialogType switch
    {
        "simple_form" => CreateSimpleFormDialog(),
        "webpage_dialog" => CreateWebpageDialog(app.Configuration, context.Log),
        "multi_step_form" => CreateMultiStepFormDialog(),
        "mixed_example" => CreateMixedExampleDialog(),
        _ => new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Unknown dialog type"))
    };
    return Task.FromResult(response);
});

teams.OnTaskSubmit(async (context, cancellationToken) =>
{
    var activity = context.Activity;
    context.Log.Info("[TASK_SUBMIT] Task submit request received");

    var data = activity.Value?.Data as JsonElement?;
    if (data == null)
    {
        context.Log.Info("[TASK_SUBMIT] No data found in the activity value");
        return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("No data found in the activity value"));
    }

    var submissionType = data.Value.TryGetProperty("submissiondialogtype", out var submissionTypeObj) && submissionTypeObj.ValueKind == JsonValueKind.String
        ? submissionTypeObj.ToString()
        : null;

    context.Log.Info($"[TASK_SUBMIT] Submission type: {submissionType}");

    string? GetFormValue(string key)
    {
        if (data.Value.TryGetProperty(key, out var val))
        {
            if (val is JsonElement element)
                return element.GetString();
            return val.ToString();
        }
        return null;
    }

    switch (submissionType)
    {
        case "simple_form":
            var name = GetFormValue("name") ?? "Unknown";
            await context.Send($"Hi {name}, thanks for submitting the form!", cancellationToken);
            return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Form was submitted"));

        case "webpage_dialog":
            var webName = GetFormValue("name") ?? "Unknown";
            var email = GetFormValue("email") ?? "No email";
            await context.Send($"Hi {webName}, thanks for submitting the form! We got that your email is {email}", cancellationToken);
            return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Form submitted successfully"));

        case "webpage_dialog_step_1":
            var nameStep1 = GetFormValue("name") ?? "Unknown";
            var nextStepCardJson = $$"""
            {
                "type": "AdaptiveCard",
                "version": "1.4",
                "body": [
                    { "type": "TextBlock", "text": "Email", "size": "Large", "weight": "Bolder" },
                    { "type": "Input.Text", "id": "email", "label": "Email", "placeholder": "Enter your email", "isRequired": true }
                ],
                "actions": [{ "type": "Action.Submit", "title": "Submit", "data": {"submissiondialogtype": "webpage_dialog_step_2", "name": "{{nameStep1}}"} }]
            }
            """;

            var nextStepCard = JsonSerializer.Deserialize<Microsoft.Teams.Cards.AdaptiveCard>(nextStepCardJson)
                ?? throw new InvalidOperationException("Failed to deserialize next step card");

            var nextStepTaskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
            {
                Title = $"Thanks {nameStep1} - Get Email",
                Card = new Microsoft.Teams.Api.Attachment
                {
                    ContentType = new Microsoft.Teams.Api.ContentType("application/vnd.microsoft.card.adaptive"),
                    Content = nextStepCard
                }
            };
            return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(nextStepTaskInfo));

        case "webpage_dialog_step_2":
            var nameStep2 = GetFormValue("name") ?? "Unknown";
            var emailStep2 = GetFormValue("email") ?? "No email";
            await context.Send($"Hi {nameStep2}, thanks for submitting the form! We got that your email is {emailStep2}", cancellationToken);
            return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Multi-step form completed successfully"));

        default:
            return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.MessageTask("Unknown submission type"));
    }
});

app.Run();

static string SanitizeForLog(string? input)
{
    if (input == null) return "";
    return input.Replace("\r", "").Replace("\n", "");
}

static Microsoft.Teams.Cards.SubmitAction CreateTaskFetchSubmitAction(string title, string dialogId)
{
    return new Microsoft.Teams.Cards.SubmitAction
    {
        Title = title,
        Data = new Microsoft.Teams.Common.Union<string, Microsoft.Teams.Cards.SubmitActionData>(
            new Microsoft.Teams.Cards.OpenDialogData(dialogId))
    };
}

static Microsoft.Teams.Cards.AdaptiveCard CreateDialogLauncherCard()
{
    var card = new Microsoft.Teams.Cards.AdaptiveCard
    {
        Body = new List<Microsoft.Teams.Cards.CardElement>
        {
            new Microsoft.Teams.Cards.TextBlock("Select the examples you want to see!")
            {
                Size = Microsoft.Teams.Cards.TextSize.Large,
                Weight = Microsoft.Teams.Cards.TextWeight.Bolder
            }
        },
        Actions = new List<Microsoft.Teams.Cards.Action>
        {
            CreateTaskFetchSubmitAction("Simple form test", "simple_form"),
            CreateTaskFetchSubmitAction("Webpage Dialog", "webpage_dialog"),
            CreateTaskFetchSubmitAction("Multi-step Form", "multi_step_form"),
            CreateTaskFetchSubmitAction("Mixed Example", "mixed_example")
        }
    };

    var serializedCard = JsonSerializer.Serialize(card, new JsonSerializerOptions { WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull });
    Console.WriteLine($"[DEBUG] Launcher Card JSON: {serializedCard}");

    return card;
}

static Microsoft.Teams.Api.TaskModules.Response CreateSimpleFormDialog()
{
    var cardJson = """
    {
        "type": "AdaptiveCard",
        "version": "1.4",
        "body": [
            { "type": "TextBlock", "text": "This is a simple form", "size": "Large", "weight": "Bolder" },
            { "type": "Input.Text", "id": "name", "label": "Name", "placeholder": "Enter your name", "isRequired": true }
        ],
        "actions": [{"type": "Action.Submit", "title": "Submit", "data": {"submissiondialogtype": "simple_form"}}]
    }
    """;

    var dialogCard = JsonSerializer.Deserialize<Microsoft.Teams.Cards.AdaptiveCard>(cardJson)
        ?? throw new InvalidOperationException("Failed to deserialize simple form card");

    var serializedCard = JsonSerializer.Serialize(dialogCard);
    Console.WriteLine($"[DEBUG] Simple Form Card JSON: {serializedCard}");

    var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
    {
        Title = "Simple Form Dialog",
        Card = new Microsoft.Teams.Api.Attachment
        {
            ContentType = new Microsoft.Teams.Api.ContentType("application/vnd.microsoft.card.adaptive"),
            Content = dialogCard
        }
    };

    var continueTask = new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo);

    Console.WriteLine($"[DEBUG] continueTask.Value is null: {continueTask.Value == null}");
    Console.WriteLine($"[DEBUG] continueTask.Value.Title: '{continueTask.Value?.Title}'");
    Console.WriteLine($"[DEBUG] continueTask.Value.Card is null: {continueTask.Value?.Card == null}");

    var debugOptions = new JsonSerializerOptions
    {
        DefaultIgnoreCondition = JsonIgnoreCondition.Never,
        WriteIndented = true
    };
    var continueTaskJson = JsonSerializer.Serialize(continueTask, debugOptions);
    Console.WriteLine($"[DEBUG] ContinueTask JSON (no ignore): {continueTaskJson}");

    var response = new Microsoft.Teams.Api.TaskModules.Response(continueTask);
    var serializedResponse = JsonSerializer.Serialize(response, debugOptions);
    Console.WriteLine($"[DEBUG] Response JSON (no ignore): {serializedResponse}");

    return response;
}

static Microsoft.Teams.Api.TaskModules.Response CreateWebpageDialog(IConfiguration configuration, Microsoft.Teams.Common.Logging.ILogger log)
{
    var botEndpoint = configuration["BotEndpoint"];
    if (string.IsNullOrEmpty(botEndpoint))
    {
        log.Warn("No remote endpoint detected. Using webpages for dialog will not work as expected");
        botEndpoint = "http://localhost:3978";
    }
    else
    {
        log.Info($"Using BotEndpoint: {botEndpoint}/tabs/dialog-form");
    }

    var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
    {
        Title = "Webpage Dialog",
        Width = new Union<int, Microsoft.Teams.Api.TaskModules.Size>(1000),
        Height = new Union<int, Microsoft.Teams.Api.TaskModules.Size>(800),
        Url = $"{botEndpoint}/tabs/dialog-form"
    };

    return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo));
}

static Microsoft.Teams.Api.TaskModules.Response CreateMultiStepFormDialog()
{
    var cardJson = """
    {
        "type": "AdaptiveCard",
        "version": "1.4",
        "body": [
            { "type": "TextBlock", "text": "This is a multi-step form", "size": "Large", "weight": "Bolder" },
            { "type": "Input.Text", "id": "name", "label": "Name", "placeholder": "Enter your name", "isRequired": true }
        ],
        "actions": [{ "type": "Action.Submit", "title": "Submit", "data": {"submissiondialogtype": "webpage_dialog_step_1"} }]
    }
    """;

    var dialogCard = JsonSerializer.Deserialize<Microsoft.Teams.Cards.AdaptiveCard>(cardJson)
        ?? throw new InvalidOperationException("Failed to deserialize multi-step form card");

    var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
    {
        Title = "Multi-step Form Dialog",
        Card = new Microsoft.Teams.Api.Attachment
        {
            ContentType = new Microsoft.Teams.Api.ContentType("application/vnd.microsoft.card.adaptive"),
            Content = dialogCard
        }
    };

    return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo));
}

static Microsoft.Teams.Api.TaskModules.Response CreateMixedExampleDialog()
{
    var taskInfo = new Microsoft.Teams.Api.TaskModules.TaskInfo
    {
        Title = "Mixed Example (C# Sample)",
        Width = new Union<int, Microsoft.Teams.Api.TaskModules.Size>(800),
        Height = new Union<int, Microsoft.Teams.Api.TaskModules.Size>(600),
        Url = "https://teams.microsoft.com/l/task/example-mixed"
    };

    return new Microsoft.Teams.Api.TaskModules.Response(new Microsoft.Teams.Api.TaskModules.ContinueTask(taskInfo));
}