import {
  EmailAddress,
  PhoneNumber,
  PostalAddress,
  TINNumber,
  UniqueID,
} from "@/core/common/domain";

import {
  type Account,
  AccountStatus,
  type IAccountProps,
  type IAccountService,
} from "@/contexts/accounts/domain";
import { ITransactionManager } from "@/core/common/infrastructure/database";
import { logger } from "@/core/logger";
import { Maybe, Result } from "@repo/rdx-utils";
import { ICreateAccountRequestDTO } from "../presentation";

export class CreateAccountUseCase {
  constructor(
    private readonly accountService: IAccountService,
    private readonly transactionManager: ITransactionManager
  ) {}

  public execute(
    accountID: UniqueID,
    dto: ICreateAccountRequestDTO
  ): Promise<Result<Account, Error>> {
    return this.transactionManager.complete(async (transaction) => {
      try {
        const validOrErrors = this.validateAccountData(dto);
        if (validOrErrors.isFailure) {
          return Result.fail(validOrErrors.error);
        }

        const data = validOrErrors.data;

        // Update account with dto
        return await this.accountService.createAccount(accountID, data, transaction);
      } catch (error: unknown) {
        logger.error(error as Error);
        return Result.fail(error as Error);
      }
    });
  }

  private validateAccountData(dto: ICreateAccountRequestDTO): Result<IAccountProps, Error> {
    const errors: Error[] = [];

    const tinOrError = TINNumber.create(dto.tin);
    const emailOrError = EmailAddress.create(dto.email);
    const phoneOrError = PhoneNumber.create(dto.phone);
    const faxOrError = PhoneNumber.createNullable(dto.fax);
    const postalAddressOrError = PostalAddress.create({
      street: dto.street,
      city: dto.city,
      state: dto.state,
      postalCode: dto.postal_code,
      country: dto.country,
    });

    const result = Result.combine([
      tinOrError,
      emailOrError,
      phoneOrError,
      faxOrError,
      postalAddressOrError,
    ]);

    if (result.isFailure) {
      return Result.fail(result.error);
    }

    const validatedData: IAccountProps = {
      status: AccountStatus.createInactive(),
      isFreelancer: dto.is_companyr,
      name: dto.name,
      tradeName: dto.trade_name ? Maybe.some(dto.trade_name) : Maybe.none(),
      tin: tinOrError.data,
      address: postalAddressOrError.data,
      email: emailOrError.data,
      phone: phoneOrError.data,
      fax: faxOrError.data,
      website: dto.website ? Maybe.some(dto.website) : Maybe.none(),
      legalRecord: dto.legal_record,
      defaultTax: dto.default_tax,
      langCode: dto.language_code,
      currencyCode: dto.currency_code,
      logo: dto.logo ? Maybe.some(dto.logo) : Maybe.none(),
    };

    if (errors.length > 0) {
      const message = errors.map((err) => err.message).toString();
      return Result.fail(new Error(message));
    }
    return Result.ok(validatedData);
  }
}
