using Books.Api.Commands.Accounts;
using Books.Api.Domain.Accounts;
using Books.Api.EventFlow.Repositories;
using EventFlow;
using Microsoft.Extensions.Logging;

namespace Books.Api.EventFlow.Subscribers;

/// <summary>
/// Service to initialize standard Danish chart of accounts for a company.
/// Called explicitly after company creation.
/// Idempotent: Safe to call multiple times for the same company.
/// </summary>
public interface IChartOfAccountsInitializer
{
    Task InitializeAsync(string companyId, CancellationToken cancellationToken = default);
}

public class ChartOfAccountsInitializer(
    ICommandBus commandBus,
    IAccountRepository accountRepository,
    ILogger<ChartOfAccountsInitializer> logger) : IChartOfAccountsInitializer
{
    public async Task InitializeAsync(string companyId, CancellationToken cancellationToken = default)
    {
        // Check for idempotency - if accounts already exist, skip initialization
        var existingAccounts = await accountRepository.GetByCompanyIdAsync(companyId, cancellationToken);
        if (existingAccounts.Count > 0)
        {
            logger.LogInformation(
                "Chart of accounts already initialized for company {CompanyId} ({Count} accounts exist)",
                companyId, existingAccounts.Count);
            return;
        }

        var standardAccounts = StandardDanishAccounts.GetAll().ToList();
        logger.LogInformation(
            "Initializing chart of accounts for company {CompanyId} with {Count} standard accounts",
            companyId, standardAccounts.Count);

        var successCount = 0;
        var errorCount = 0;

        foreach (var account in standardAccounts)
        {
            cancellationToken.ThrowIfCancellationRequested();

            try
            {
                var accountId = AccountId.FromCompanyAndNumber(companyId, account.AccountNumber);

                var command = new CreateAccountCommand(
                    accountId,
                    companyId,
                    account.AccountNumber,
                    account.Name,
                    account.AccountType,
                    parentId: null,
                    account.Description,
                    account.DefaultVatCode,
                    isSystemAccount: account.IsSystemAccount,
                    standardAccountNumber: account.StandardAccountNumber);

                await commandBus.PublishAsync(command, cancellationToken);
                successCount++;
            }
            catch (Exception ex)
            {
                errorCount++;
                logger.LogWarning(ex,
                    "Failed to create account {AccountNumber} ({AccountName}) for company {CompanyId}",
                    account.AccountNumber, account.Name, companyId);
                // Continue with remaining accounts - partial initialization is better than none
            }
        }

        if (errorCount > 0)
        {
            logger.LogWarning(
                "Chart of accounts initialization completed for company {CompanyId} with {SuccessCount} accounts created and {ErrorCount} errors",
                companyId, successCount, errorCount);
        }
        else
        {
            logger.LogInformation(
                "Chart of accounts initialization completed for company {CompanyId} - {SuccessCount} accounts created",
                companyId, successCount);
        }
    }
}
