using Books.Api.Commands.Companies;
using Books.Api.Domain.Companies;
using Books.Api.EventFlow.Repositories;
using Books.Api.GraphQL.InputTypes;
using Books.Api.GraphQL.Types;
using EventFlow;
using GraphQL;
using GraphQL.Types;

namespace Books.Api.GraphQL.Mutations;

public class BooksMutation : ObjectGraphType
{
    public BooksMutation()
    {
        Name = "Mutation";
        Description = "Root mutation for the Books API";

        // createCompany(input: CreateCompanyInput!): CompanyType
        Field<CompanyType>("createCompany")
            .Description("Create a new company")
            .Argument<NonNullGraphType<CreateCompanyInputType>>("input", "The company data")
            .ResolveAsync(async ctx =>
            {
                var input = ctx.GetArgument<CreateCompanyInput>("input");
                var commandBus = ctx.RequestServices!.GetRequiredService<ICommandBus>();
                var repository = ctx.RequestServices!.GetRequiredService<ICompanyRepository>();

                var companyId = CompanyId.New;

                var command = new CreateCompanyCommand(
                    companyId,
                    input.Name,
                    input.Cvr,
                    input.Address,
                    input.PostalCode,
                    input.City,
                    input.Country ?? "DK",
                    input.FiscalYearStartMonth ?? 1,
                    input.Currency ?? "DKK",
                    input.VatRegistered ?? false,
                    input.VatPeriodFrequency);

                await commandBus.PublishAsync(command, ctx.CancellationToken);

                // Return the created company (eventually consistent)
                return await repository.GetByIdAsync(companyId.Value, ctx.CancellationToken);
            });

        // updateCompany(id: ID!, input: UpdateCompanyInput!): CompanyType
        Field<CompanyType>("updateCompany")
            .Description("Update an existing company")
            .Argument<NonNullGraphType<IdGraphType>>("id", "The company ID")
            .Argument<NonNullGraphType<UpdateCompanyInputType>>("input", "The updated company data")
            .ResolveAsync(async ctx =>
            {
                var id = ctx.GetArgument<string>("id");
                var input = ctx.GetArgument<UpdateCompanyInput>("input");
                var commandBus = ctx.RequestServices!.GetRequiredService<ICommandBus>();
                var repository = ctx.RequestServices!.GetRequiredService<ICompanyRepository>();

                var companyId = CompanyId.With(id);

                var command = new UpdateCompanyCommand(
                    companyId,
                    input.Name,
                    input.Cvr,
                    input.Address,
                    input.PostalCode,
                    input.City,
                    input.Country ?? "DK",
                    input.FiscalYearStartMonth ?? 1,
                    input.Currency ?? "DKK",
                    input.VatRegistered ?? false,
                    input.VatPeriodFrequency);

                await commandBus.PublishAsync(command, ctx.CancellationToken);

                return await repository.GetByIdAsync(companyId.Value, ctx.CancellationToken);
            });
    }
}
