import { AppDataSource } from "../database/data-source";
import { OrgRevision } from "../entities/OrgRevision";
import { Profile } from "../entities/Profile";
import { PosMaster } from "../entities/PosMaster";

interface LogCacheData {
  currentRevision: OrgRevision | null;
  profileCache: Map<string, Profile>; // keycloak → Profile
  rootIdCache: Map<string, string>; // profileId → rootId
  updatedAt: Date;
}

class LogMemoryStore {
  private cache: LogCacheData = {
    currentRevision: null,
    profileCache: new Map(),
    rootIdCache: new Map(),
    updatedAt: new Date(),
  };
  private readonly CACHE_TTL = 60 * 60 * 1000; // 60 minutes
  private isInitialized = false;

  constructor() {
    // ไม่ refresh ทันที - รอให้เรียก initialize() หลัง TypeORM ready
  }

  // เริ่มต้น cache หลังจาก TypeORM initialize เสร็จ
  initialize() {
    if (this.isInitialized) {
      console.log("[LogMemoryStore] Already initialized");
      return;
    }

    this.isInitialized = true;
    this.refreshCache();

    console.log(
      "[LogMemoryStore] Initialized with",
      this.CACHE_TTL / 1000 / 60,
      "minute TTL (passive cleanup on access)",
    );
  }

  private async refreshCache() {
    try {
      // Refresh revision cache
      const repoRevision = AppDataSource.getRepository(OrgRevision);
      const revision = await repoRevision.findOne({
        where: {
          orgRevisionIsCurrent: true,
          orgRevisionIsDraft: false,
        },
      });
      this.cache.currentRevision = revision;

      // Clear on-demand caches (they will be rebuilt as needed)
      this.cache.profileCache.clear();
      this.cache.rootIdCache.clear();

      this.cache.updatedAt = new Date();
      console.log("[LogMemoryStore] Cache refreshed at", this.cache.updatedAt.toISOString());
    } catch (error) {
      console.error("[LogMemoryStore] Error refreshing cache:", error);
    }
  }

  // Check if cache is stale and refresh if needed
  private async checkAndRefreshIfNeeded() {
    const now = new Date();
    const age = now.getTime() - this.cache.updatedAt.getTime();
    if (age > this.CACHE_TTL) {
      console.log(
        "[LogMemoryStore] Cache is stale (age:",
        Math.round(age / 1000 / 60),
        "minutes), refreshing...",
      );
      await this.refreshCache();
    }
  }

  getCurrentRevision(): OrgRevision | null {
    // Check for stale data (fire and forget)
    this.checkAndRefreshIfNeeded();
    return this.cache.currentRevision;
  }

  getLastUpdateTime(): Date {
    return this.cache.updatedAt;
  }

  /**
   * Get Profile by keycloak ID with caching
   */
  async getProfileByKeycloak(keycloak: string): Promise<Profile | null> {
    // Check for stale data
    await this.checkAndRefreshIfNeeded();

    // Check cache first
    if (this.cache.profileCache.has(keycloak)) {
      return this.cache.profileCache.get(keycloak)!;
    }

    // Fetch from database
    const repoProfile = AppDataSource.getRepository(Profile);
    const profile = await repoProfile.findOne({
      where: { keycloak },
    });

    // Cache the result
    if (profile) {
      this.cache.profileCache.set(keycloak, profile);
    }

    return profile;
  }

  /**
   * Get RootId by profileId with caching
   */
  async getRootIdByProfileId(profileId: string | undefined): Promise<string | null> {
    if (!profileId) return null;

    // Check for stale data
    await this.checkAndRefreshIfNeeded();

    // Check cache first
    if (this.cache.rootIdCache.has(profileId)) {
      return this.cache.rootIdCache.get(profileId)!;
    }

    // Fetch from database
    const repoPosmaster = AppDataSource.getRepository(PosMaster);
    const revision = this.getCurrentRevision();
    //
    const posMaster = await repoPosmaster.findOne({
      where: {
        current_holderId: profileId,
        orgRevisionId: revision?.id,
      },
      relations: ["orgRoot"],
      select: {
        orgRoot: {
          ancestorDNA: true,
        },
      },
    });

    const rootId = posMaster?.orgRoot?.ancestorDNA ?? null;

    // Cache the result
    if (rootId) {
      this.cache.rootIdCache.set(profileId, rootId);
    }

    return rootId;
  }

  // สำหรับ shutdown
  destroy() {
    // No active timer to clear
    console.log("[LogMemoryStore] Destroyed");
  }
}

export const logMemoryStore = new LogMemoryStore();
