import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from "@nestjs/common";
import { Observable } from "rxjs";
import { map } from "rxjs/operators";
import { ApiResponse, createSuccessResponse } from "../types/api-response.type";

/**
 * Response interceptor that wraps all successful responses
 * in the standard ApiResponse format
 */
import { I18nService, I18nContext } from "nestjs-i18n";

@Injectable()
export class ResponseInterceptor<T> implements NestInterceptor<
  T,
  ApiResponse<T>
> {
  constructor(private readonly i18n: I18nService) {}

  intercept(
    context: ExecutionContext,
    next: CallHandler,
  ): Observable<ApiResponse<T>> {
    return next.handle().pipe(
      map((data: unknown) => {
        const request = context.switchToHttp().getRequest();

        // Determine language
        const i18nContext = I18nContext.current();
        let lang = i18nContext?.lang;

        if (!lang) {
          const acceptLanguage = request.headers["accept-language"];
          const xLang = request.headers["x-lang"];

          if (xLang) {
            lang = Array.isArray(xLang) ? xLang[0] : xLang;
          } else if (acceptLanguage) {
            lang = acceptLanguage.split(",")[0].split(";")[0].split("-")[0];
          }
        }

        lang = lang || "en";

        // If data is already an ApiResponse, we should still translate its 'data' property
        // But first let's just do it directly on 'data' below before returning
        if (this.isApiResponse(data)) {
          if (data !== null) {
            try {
              this.translateReasons(data, lang);
            } catch {
              // Ignore if object is not extensible
            }
          }
          return data as ApiResponse<T>;
        }

        // Recursively translate reasons arrays in the response body
        if (data !== null) {
          try {
            this.translateReasons(data, lang);
          } catch {
            // Ignore if object is not extensible
          }
        }

        const message = this.i18n.translate("common.success", {
          lang,
        });

        // Wrap in success response
        return createSuccessResponse(data as T, message);
      }),
    );
  }

  private translateReasons(data: any, lang: string) {
    if (!data || typeof data !== "object") {
      return;
    }

    if (Array.isArray(data)) {
      data.forEach((item) => this.translateReasons(item, lang));
      return;
    }

    Object.keys(data).forEach((key) => {
      const val = data[key];
      if (
        (key === "reasons" ||
          key === "decision_reasons" ||
          key === "reasoning_factors") &&
        Array.isArray(val)
      ) {
        data[key] = val.map((r: any) => {
          if (typeof r !== "string") return r;
          const translationKey = `predictions.reasons.${r}`;
          const translated = this.i18n.translate(translationKey, {
            lang,
          });
          return translated === translationKey ? r : translated;
        });
      } else if (key === "reason" && typeof val === "string") {
        const translationKey = `predictions.reasons.${val}`;
        const translated = this.i18n.translate(translationKey, {
          lang,
        });
        data[key] = translated === translationKey ? val : translated;
      } else if (key === "flags" && Array.isArray(val)) {
        data[key] = val.map((r: any) => {
          if (typeof r !== "string") return r;
          const translationKey = `predictions.flags.${r}`;
          const translated = this.i18n.translate(translationKey, {
            lang,
          });
          return translated === translationKey ? r : translated;
        });
      } else if (key === "warnings" && Array.isArray(val)) {
        data[key] = val.map((r: any) => {
          if (typeof r !== "string") return r;
          const translationKey = `predictions.warnings.${r}`;
          const translated = this.i18n.translate(translationKey, {
            lang,
          });
          return translated === translationKey ? r : translated;
        });
      } else if (typeof val === "object" && val !== null) {
        this.translateReasons(val, lang);
      }
    });
  }

  private isApiResponse(data: unknown): boolean {
    return (
      data !== null &&
      typeof data === "object" &&
      "success" in data &&
      "status" in data &&
      "message" in data &&
      "data" in data
    );
  }
}
