import cron from 'node-cron';
import dbManager from '../db/databaseManager.js';
import { logger } from '../utils/logger.js';

class ProjectMetadataCache {
  constructor() {
    this.roomMap = new Map(); // device_id -> room_type_id
    this.loopMap = new Map(); // room_type_id:loop_address -> loop_name
  }

  async init() {
    try {
      await this.refresh();
    } catch (error) {
      logger.error('Initial metadata refresh failed', { error: error.message });
    }
    
    // Schedule 1:00 AM daily
    cron.schedule('0 1 * * *', () => {
      this.refresh().catch(err => logger.error('Scheduled metadata refresh failed', { error: err.message }));
    });
  }

  async refresh() {
    logger.info('Refreshing project metadata cache...');
    const client = await dbManager.pool.connect();
    try {
      // Load Rooms
      // temporary_project.rooms might be partitioned, but querying parent works.
      const roomsRes = await client.query('SELECT device_id, room_type_id FROM temporary_project.rooms');
      const newRoomMap = new Map();
      for (const row of roomsRes.rows) {
        if (row.device_id) {
          newRoomMap.set(row.device_id, row.room_type_id);
        }
      }

      // Load Loops
      const loopsRes = await client.query('SELECT room_type_id, loop_address, loop_name FROM temporary_project.loops');
      const newLoopMap = new Map();
      for (const row of loopsRes.rows) {
        if (row.room_type_id && row.loop_address) {
          // loop_address is varchar, we will key it as string
          const key = `${row.room_type_id}:${row.loop_address}`;
          newLoopMap.set(key, row.loop_name);
        }
      }

      this.roomMap = newRoomMap;
      this.loopMap = newLoopMap;
      logger.info('Project metadata cache refreshed', { 
        roomsCount: this.roomMap.size, 
        loopsCount: this.loopMap.size 
      });

    } catch (error) {
      // If schema/tables don't exist, this will throw.
      // We log but don't crash the app, as this is an enhancement feature.
      logger.error('Failed to refresh project metadata', { error: error.message });
      throw error;
    } finally {
      client.release();
    }
  }

  /**
   * Get loop name for a given device configuration
   * @param {string} deviceId - The device ID (from room)
   * @param {number|string} devType - The device type
   * @param {number|string} devAddr - The device address
   * @param {number|string} devLoop - The device loop
   * @returns {string|null} - The loop name or null if not found
   */
  getLoopName(deviceId, devType, devAddr, devLoop) {
    if (!deviceId || 
        devType === undefined || devType === null ||
        devAddr === undefined || devAddr === null ||
        devLoop === undefined || devLoop === null) {
      return null;
    }
    
    const roomTypeId = this.roomMap.get(deviceId);
    if (!roomTypeId) return null;

    // Construct loop_address: 3-digit zero-padded concatenation of type, addr, loop
    // e.g. type=1, addr=23, loop=12 -> 001023012
    const fmt = (val) => String(val).padStart(3, '0');
    const loopAddress = `${fmt(devType)}${fmt(devAddr)}${fmt(devLoop)}`;

    const key = `${roomTypeId}:${loopAddress}`;
    return this.loopMap.get(key) || null;
  }
}

export default new ProjectMetadataCache();
