import { Injectable, Inject } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { FreebitOrchestratorService } from "@bff/integrations/freebit/services/freebit-orchestrator.service";
import { SimValidationService } from "./sim-validation.service";
import { SimUsageStoreService } from "../../sim-usage-store.service";
import { getErrorMessage } from "@bff/core/utils/error.util";
import type { SimUsage, SimTopUpHistory } from "@bff/integrations/freebit/interfaces/freebit.types";
import type { SimTopUpHistoryRequest } from "../types/sim-requests.types";
import { BadRequestException } from "@nestjs/common";

@Injectable()
export class SimUsageService {
  constructor(
    private readonly freebitService: FreebitOrchestratorService,
    private readonly simValidation: SimValidationService,
    private readonly usageStore: SimUsageStoreService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  /**
   * Get SIM data usage for a subscription
   */
  async getSimUsage(userId: string, subscriptionId: number): Promise<SimUsage> {
    let account = "";

    try {
      const validation = await this.simValidation.validateSimSubscription(userId, subscriptionId);
      account = validation.account;

      const simUsage = await this.freebitService.getSimUsage(account);

      // Persist today's usage for monthly charts and cleanup previous months
      try {
        await this.usageStore.upsertToday(account, simUsage.todayUsageMb);
        await this.usageStore.cleanupPreviousMonths();
        const stored = await this.usageStore.getLastNDays(account, 30);
        if (stored.length > 0) {
          simUsage.recentDaysUsage = stored.map(d => ({
            date: d.date,
            usageKb: Math.round(d.usageMb * 1000),
            usageMb: d.usageMb,
          }));
        }
      } catch (e) {
        const sanitizedError = getErrorMessage(e);
        this.logger.warn("SIM usage persistence failed (non-fatal)", {
          account,
          error: sanitizedError,
        });
      }

      this.logger.log(`Retrieved SIM usage for subscription ${subscriptionId}`, {
        userId,
        subscriptionId,
        account,
        todayUsageMb: simUsage.todayUsageMb,
      });

      return simUsage;
    } catch (error) {
      const sanitizedError = getErrorMessage(error);
      this.logger.error(`Failed to get SIM usage for subscription ${subscriptionId}`, {
        error: sanitizedError,
        userId,
        subscriptionId,
        account,
      });

      if (account && sanitizedError.toLowerCase().includes("failed to get sim usage")) {
        try {
          const fallback = await this.buildFallbackUsage(account);
          this.logger.warn("Serving cached SIM usage after Freebit failure", {
            userId,
            subscriptionId,
            account,
            fallbackSource: fallback.recentDaysUsage.length > 0 ? "cache" : "default",
          });
          return fallback;
        } catch (fallbackError) {
          this.logger.warn("Unable to build fallback SIM usage", {
            account,
            error: getErrorMessage(fallbackError),
          });
        }
      }

      throw error;
    }
  }

  private async buildFallbackUsage(account: string): Promise<SimUsage> {
    try {
      const records = await this.usageStore.getLastNDays(account, 30);
      if (records.length > 0) {
        const todayIso = new Date().toISOString().slice(0, 10);
        const todayRecord = records.find(r => r.date === todayIso) ?? records[records.length - 1];
        const todayUsageMb = todayRecord?.usageMb ?? 0;

        const mostRecentDate = records[0]?.date;

        return {
          account,
          todayUsageMb,
          todayUsageKb: Math.round(todayUsageMb * 1000),
          recentDaysUsage: records.map(r => ({
            date: r.date,
            usageMb: r.usageMb,
            usageKb: Math.round(r.usageMb * 1000),
          })),
          isBlacklisted: false,
          lastUpdated: mostRecentDate ? `${mostRecentDate}T00:00:00.000Z` : new Date().toISOString(),
        };
      }
    } catch (error) {
      this.logger.warn("Failed to load cached SIM usage", {
        account,
        error: getErrorMessage(error),
      });
    }

    return {
      account,
      todayUsageMb: 0,
      todayUsageKb: 0,
      recentDaysUsage: [],
      isBlacklisted: false,
      lastUpdated: new Date().toISOString(),
    };
  }

  /**
   * Get SIM top-up history
   */
  async getSimTopUpHistory(
    userId: string,
    subscriptionId: number,
    request: SimTopUpHistoryRequest
  ): Promise<SimTopUpHistory> {
    try {
      const { account } = await this.simValidation.validateSimSubscription(userId, subscriptionId);

      // Validate date format
      if (!/^\d{8}$/.test(request.fromDate) || !/^\d{8}$/.test(request.toDate)) {
        throw new BadRequestException("Dates must be in YYYYMMDD format");
      }

      const history = await this.freebitService.getSimTopUpHistory(
        account,
        request.fromDate,
        request.toDate
      );

      this.logger.log(`Retrieved SIM top-up history for subscription ${subscriptionId}`, {
        userId,
        subscriptionId,
        account,
        totalAdditions: history.totalAdditions,
      });

      return history;
    } catch (error) {
      const sanitizedError = getErrorMessage(error);
      this.logger.error(`Failed to get SIM top-up history for subscription ${subscriptionId}`, {
        error: sanitizedError,
        userId,
        subscriptionId,
      });
      throw error;
    }
  }
}
