/**
 * Service responsible for WHMCS client creation and cleanup during signup
 */
import {
  Injectable,
  Inject,
  BadRequestException,
  ConflictException,
  HttpStatus,
} from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { Logger } from "nestjs-pino";
import { WhmcsAccountDiscoveryService } from "@bff/integrations/whmcs/services/whmcs-account-discovery.service.js";
import { WhmcsClientService } from "@bff/integrations/whmcs/services/whmcs-client.service.js";
import { MappingsService } from "@bff/modules/id-mappings/mappings.service.js";
import { extractErrorMessage } from "@bff/core/utils/error.util.js";
import { DomainHttpException } from "@bff/core/http/domain-http.exception.js";
import { ErrorCode } from "@customer-portal/domain/common";
import { serializeWhmcsKeyValueMap } from "@customer-portal/domain/customer/providers";
import type { SignupRequest } from "@customer-portal/domain/auth";

export interface WhmcsClientCreationParams {
  firstName: string;
  lastName: string;
  email: string;
  password: string;
  company?: string;
  phone: string;
  address: {
    address1: string;
    address2?: string;
    city: string;
    state: string;
    postcode: string;
    country: string;
  };
  customerNumber: string | null;
  dateOfBirth?: string | null;
  gender?: string | null;
  nationality?: string | null;
}

export interface WhmcsCreatedClient {
  clientId: number;
}

@Injectable()
export class SignupWhmcsService {
  constructor(
    private readonly whmcsClientService: WhmcsClientService,
    private readonly discoveryService: WhmcsAccountDiscoveryService,
    private readonly mappingsService: MappingsService,
    private readonly configService: ConfigService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  /**
   * Check if WHMCS client already exists for email
   * Throws ConflictException or DomainHttpException if client exists
   */
  async checkExistingClient(email: string): Promise<void> {
    const existingWhmcs = await this.discoveryService.findClientByEmail(email);
    if (!existingWhmcs) {
      return;
    }

    const existingMapping = await this.mappingsService.findByWhmcsClientId(existingWhmcs.id);
    if (existingMapping) {
      throw new ConflictException("You already have an account. Please sign in.");
    }

    throw new DomainHttpException(ErrorCode.LEGACY_ACCOUNT_EXISTS, HttpStatus.CONFLICT);
  }

  /**
   * Create a new WHMCS client for signup
   */
  async createClient(params: WhmcsClientCreationParams): Promise<WhmcsCreatedClient> {
    const customerNumberFieldId = this.configService.get<string>("WHMCS_CUSTOMER_NUMBER_FIELD_ID");
    const dobFieldId = this.configService.get<string>("WHMCS_DOB_FIELD_ID");
    const genderFieldId = this.configService.get<string>("WHMCS_GENDER_FIELD_ID");
    const nationalityFieldId = this.configService.get<string>("WHMCS_NATIONALITY_FIELD_ID");

    const customfieldsMap: Record<string, string> = {};
    if (customerNumberFieldId && params.customerNumber) {
      customfieldsMap[customerNumberFieldId] = params.customerNumber;
    }
    if (dobFieldId && params.dateOfBirth) customfieldsMap[dobFieldId] = params.dateOfBirth;
    if (genderFieldId && params.gender) customfieldsMap[genderFieldId] = params.gender;
    if (nationalityFieldId && params.nationality)
      customfieldsMap[nationalityFieldId] = params.nationality;

    this.logger.log("Creating WHMCS client", {
      email: params.email,
      firstName: params.firstName,
      lastName: params.lastName,
      sfNumber: params.customerNumber,
    });

    try {
      const whmcsClient = await this.whmcsClientService.addClient({
        firstname: params.firstName,
        lastname: params.lastName,
        email: params.email,
        companyname: params.company || "",
        phonenumber: params.phone,
        address1: params.address.address1,
        address2: params.address.address2 ?? "",
        city: params.address.city,
        state: params.address.state,
        postcode: params.address.postcode,
        country: params.address.country,
        password2: params.password,
        customfields: serializeWhmcsKeyValueMap(customfieldsMap) || undefined,
      });

      this.logger.log("WHMCS client created successfully", {
        clientId: whmcsClient.clientId,
        email: params.email,
      });

      return { clientId: whmcsClient.clientId };
    } catch (whmcsError) {
      this.logger.error(
        {
          error: extractErrorMessage(whmcsError),
          email: params.email,
          firstName: params.firstName,
          lastName: params.lastName,
        },
        "Failed to create WHMCS client"
      );
      throw new BadRequestException(
        `Failed to create billing account: ${extractErrorMessage(whmcsError)}`
      );
    }
  }

  /**
   * Mark orphaned WHMCS client for cleanup
   * Called when database transaction fails after WHMCS client creation
   */
  async markClientForCleanup(clientId: number, email: string): Promise<void> {
    try {
      await this.whmcsClientService.updateClient(clientId, {
        status: "Inactive",
      });

      this.logger.warn("Marked orphaned WHMCS client for manual cleanup", {
        whmcsClientId: clientId,
        email,
        action: "marked_for_cleanup",
      });
    } catch (cleanupError) {
      this.logger.error("Failed to mark orphaned WHMCS client for cleanup", {
        whmcsClientId: clientId,
        email,
        cleanupError: extractErrorMessage(cleanupError),
        recommendation: "Manual cleanup required in WHMCS admin",
      });
    }
  }

  /**
   * Validate address data for WHMCS client creation
   */
  validateAddressData(signupData: SignupRequest): void {
    const { phone, address } = signupData;

    if (
      !address?.address1 ||
      !address?.city ||
      !address?.state ||
      !address?.postcode ||
      !address?.country
    ) {
      throw new BadRequestException(
        "Complete address information is required for billing account creation"
      );
    }

    if (!phone) {
      throw new BadRequestException("Phone number is required for billing account creation");
    }
  }
}
