using System.Diagnostics;
using System.IO.Pipelines;
using System.Text;
using System.Text.Json;

using Microsoft.AspNetCore.Mvc;

namespace JsonWebApp.Controllers;

[ApiController]
public class JobController : ControllerBase
{
    // Zmień na #if false by przełączyć się na wersję o niskim zużyciu pamięci z listingu 8.
#if true
    [HttpPost]
    [Route("/jobs/create")]
    public void CreateJob([FromBody] JobDescription requestBody)
    {
        switch (requestBody.JobCategory)
        {
            case "arduous":
                CreateArduousJob(requestBody.DepartmentId);
                break;

            case "tedious":
                CreateTediousJob(requestBody.DepartmentId);
                break;
        }
    }

    public record JobDescription(int DepartmentId, string JobCategory);

#else

        private static readonly byte[] Utf8TextJobCategory =
            Encoding.UTF8.GetBytes("JobCategory");
        private static readonly byte[] Utf8TextDepartmentId =
            Encoding.UTF8.GetBytes("DepartmentId");
        private static readonly byte[] Utf8TextArduous = Encoding.UTF8.GetBytes("arduous");
        private static readonly byte[] Utf8TextTedious = Encoding.UTF8.GetBytes("tedious");

        [HttpPost]
        [Route("/jobs/create")]
        public async ValueTask CreateJobFrugalAsync()
        {
            bool inDepartmentIdProperty = false;
            bool inJobCategoryProperty = false;
            int? departmentId = null;
            bool? isArduous = null;

            PipeReader reader = this.Request.BodyReader;
            JsonReaderState jsonState = default;
            while (true)
            {
                ReadResult result = await reader.ReadAsync().ConfigureAwait(false);
                jsonState = ProcessBuffer(
                    result,
                    jsonState,
                    out SequencePosition position);

                if (departmentId.HasValue && isArduous.HasValue)
                {
                    if (isArduous.Value)
                    {
                        CreateArduousJob(departmentId.Value);
                    }
                    else
                    {
                        CreateTediousJob(departmentId.Value);
                    }

                    return;
                }

                reader.AdvanceTo(position);

                if (result.IsCompleted)
                {
                    break;
                }
            }

            JsonReaderState ProcessBuffer(
                in ReadResult result,
                in JsonReaderState jsonState,
                out SequencePosition position)
            {
                // To dane typu ref struct, zatem nie powodują narzutów związanych z odzyskiwaniem pamięci
                var r = new Utf8JsonReader(result.Buffer, result.IsCompleted, jsonState);

                while (r.Read())
                {
                    if (inDepartmentIdProperty)
                    {
                        if (r.TokenType == JsonTokenType.Number)
                        {
                            if (r.TryGetInt32(out int v))
                            {
                                departmentId = v;
                            }
                        }
                    }
                    else if (inJobCategoryProperty)
                    {
                        if (r.TokenType == JsonTokenType.String)
                        {
                            if (r.ValueSpan.SequenceEqual(Utf8TextArduous))
                            {
                                isArduous = true;
                            }
                            else if (r.ValueSpan.SequenceEqual(Utf8TextTedious))
                            {
                                isArduous = false;
                            }
                        }
                    }

                    inDepartmentIdProperty = false;
                    inJobCategoryProperty = false;

                    if (r.TokenType == JsonTokenType.PropertyName)
                    {
                        if (r.ValueSpan.SequenceEqual(Utf8TextJobCategory))
                        {
                            inJobCategoryProperty = true;
                        }
                        else if (r.ValueSpan.SequenceEqual(Utf8TextDepartmentId))
                        {
                            inDepartmentIdProperty = true;
                        }
                    }
                }

                position = r.Position;
                return r.CurrentState;
            }
        }

    public record JobDescription(int DepartmentId, string JobCategory);
#endif
    private static void CreateTediousJob(int departmentId)
    {
        Debug.WriteLine($"Rzeczywisty kod w tym miejscu tworzyłby jakieś pracochłonne zadanie dla departamentu {departmentId}");
    }

    private static void CreateArduousJob(int departmentId)
    {
        Debug.WriteLine($"Rzeczywisty kod w tym miejscu tworzyłby jakieś trudne zadanie dla departamentu {departmentId}");
    }
}