import { Injectable, Inject } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { promises as fs } from "fs";
import { join } from "path";

export interface TestTrackingRecord {
  timestamp: string;
  apiEndpoint: string;
  apiMethod: string;
  phoneNumber: string;
  simIdentifier?: string;
  requestPayload?: string;
  responseStatus?: string;
  error?: string;
  additionalInfo?: string;
}

/**
 * Service for tracking physical SIM test API calls
 * Logs all API calls to a CSV file for testing purposes
 */
@Injectable()
export class FreebitTestTrackerService {
  private readonly logFilePath: string;
  private readonly csvHeaders = [
    "Timestamp",
    "API Endpoint",
    "API Method",
    "Phone Number",
    "SIM Identifier",
    "Request Payload",
    "Response Status",
    "Error",
    "Additional Info",
  ];

  constructor(@Inject(Logger) private readonly logger: Logger) {
    // Store log file in project root
    const projectRoot = process.cwd();
    this.logFilePath = join(projectRoot, "sim-api-test-log.csv");

    // Initialize CSV file with headers if it doesn't exist
    this.initializeLogFile().catch((error: unknown) => {
      this.logger.error("Failed to initialize test tracking log file", {
        error: error instanceof Error ? error.message : String(error),
      });
    });
  }

  /**
   * Initialize the CSV log file with headers if it doesn't exist
   */
  private async initializeLogFile(): Promise<void> {
    try {
      await fs.access(this.logFilePath);
      // File exists, no need to write headers
    } catch {
      // File doesn't exist, create it with headers
      const headers = this.csvHeaders.join(",") + "\n";
      await fs.writeFile(this.logFilePath, headers, "utf-8");
      this.logger.log("Created test tracking log file", { path: this.logFilePath });
    }
  }

  /**
   * Log an API call to the CSV file
   */
  async logApiCall(record: TestTrackingRecord): Promise<void> {
    try {
      await this.initializeLogFile();

      // Format the record as CSV row
      const row =
        [
          record.timestamp,
          this.escapeCsvField(record.apiEndpoint),
          this.escapeCsvField(record.apiMethod),
          this.escapeCsvField(record.phoneNumber),
          this.escapeCsvField(record.simIdentifier || ""),
          this.escapeCsvField(record.requestPayload || ""),
          this.escapeCsvField(record.responseStatus || ""),
          this.escapeCsvField(record.error || ""),
          this.escapeCsvField(record.additionalInfo || ""),
        ].join(",") + "\n";

      // Append to file
      await fs.appendFile(this.logFilePath, row, "utf-8");

      this.logger.debug("Logged API call to test tracking file", {
        endpoint: record.apiEndpoint,
        phoneNumber: record.phoneNumber,
      });
    } catch (error) {
      // Don't throw - logging failures shouldn't break the API
      this.logger.error("Failed to log API call to test tracking file", {
        error: error instanceof Error ? error.message : String(error),
        record,
      });
    }
  }

  /**
   * Escape CSV field values (handle commas, quotes, newlines)
   */
  private escapeCsvField(field: string): string {
    if (!field) return "";

    // If field contains comma, quote, or newline, wrap in quotes and escape quotes
    if (field.includes(",") || field.includes('"') || field.includes("\n")) {
      return `"${field.replace(/"/g, '""')}"`;
    }

    return field;
  }

  /**
   * Extract phone number from account or payload
   */
  extractPhoneNumber(account: string, payload?: unknown): string {
    if (account) return account;

    // Try to extract from payload if it's an object
    if (payload && typeof payload === "object") {
      const obj = payload as Record<string, unknown>;
      return (
        (obj["account"] as string) ||
        (obj["msisdn"] as string) ||
        (obj["phoneNumber"] as string) ||
        ""
      );
    }

    return "";
  }

  /**
   * Format timestamp as ISO string
   */
  getCurrentTimestamp(): string {
    return new Date().toISOString();
  }
}
