/**
 * Timer light rule
 *
 * - btn_down: Light goes off
 * - long_push: Flash to confirm, enter "count mode" - counts seconds until next btn_down, then light goes on
 * - Normal btn_down (no long_push): Light goes off, then turns back on after the stored count elapsed
 *
 * Also syncs remote switch CC8DA243B0A0 inversely (light off = switch on, light on = switch off)
 *
 * Telegram bot (remote control):
 *   /open     — Open valve
 *   /close    — Close valve
 *   /run      — Close valve then reopen after stored duration
 *   /duration — Get or set timer duration (e.g. 30s, 2m, 10000)
 *   /status   — Show current status
 */

import fs from 'fs';
import path from 'path';
import { startStatusServer } from '../waterButtonStatusServer.js';
import { startTelegramBot } from '../waterButtonTelegramBot.js';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
const STATE_FILE = path.join(__dirname, 'timer_state.json');
const WATER_BUTTON_MAC = '08A6F773510C';
const REMOTE_SWITCH_MAC = 'CC8DA243B0A0';

// Telegram



// sendRPC / getState persisted across hot reloads via globals (populated on first ctx event)
if (!global.__waterBotRPC) global.__waterBotRPC = null;
if (!global.__waterBotGetState) global.__waterBotGetState = null;

// ── Device helpers ────────────────────────────────────────────────────────────

async function setLight(sendRPC, mac, on, brightness) {
  await sendRPC(mac, 'Light.Set', { id: 0, on, brightness });
  // Remote switch is inverse: light off → switch on, light on → switch off
  await sendRPC(REMOTE_SWITCH_MAC, 'Switch.Set', { id: 0, on: !on });
}

// ── Persistence ───────────────────────────────────────────────────────────────

function loadPersistedState() {
  try {
    if (fs.existsSync(STATE_FILE)) {
      return JSON.parse(fs.readFileSync(STATE_FILE, 'utf8'));
    }
  } catch (err) {
    console.error('Error loading state:', err);
  }
  return {};
}

function saveState(state) {
  try {
    const toSave = {};
    for (const [mac, data] of Object.entries(state)) {
      toSave[mac] = { storedDuration: data.storedDuration };
    }
    fs.writeFileSync(STATE_FILE, JSON.stringify(toSave, null, 2));
  } catch (err) {
    console.error('Error saving state:', err);
  }
}

// ── In-memory device state ────────────────────────────────────────────────────

const persistedState = loadPersistedState();
const deviceState = new Map();

function getState(mac) {
  if (!deviceState.has(mac)) {
    const persisted = persistedState[mac] || {};
    deviceState.set(mac, {
      countMode: false,
      countStart: 0,
      storedDuration: persisted.storedDuration || 5000,
      timer: null,
      timerStartedAt: null,
      timerEndsAt: null
    });
  }
  return deviceState.get(mac);
}


startTelegramBot({
  getState,
  WATER_BUTTON_MAC,
  REMOTE_SWITCH_MAC,
  setLight,
  persistedState,
  saveState
});

// ── Rule export ───────────────────────────────────────────────────────────────

export default {
  getStatus() {
    const state = getState(WATER_BUTTON_MAC);
    return {
      storedDuration: state.storedDuration,
      countMode: state.countMode,
      timerActive: state.timer !== null
    };
  },

  setConfig(key, value) {
    if (key === 'storedDuration') {
      const duration = parseInt(value, 10);
      if (duration > 0 && duration <= 300000) {
        const state = getState(WATER_BUTTON_MAC);
        state.storedDuration = duration;
        persistedState[WATER_BUTTON_MAC] = { storedDuration: duration };
        saveState(persistedState);
        console.log(`[Rule] storedDuration set to ${duration}ms`);
        return true;
      }
    }
    return false;
  },

  async run(ctx) {
    // Make sendRPC and getState available to the Telegram bot handlers
    global.__waterBotRPC = ctx.sendRPC;
    global.__waterBotGetState = ctx.getState;

    // ── Online / offline events ──────────────────────────────────────────

    // Water button comes online — turn light on if remote switch is also online
    if (ctx.trigger.mac === WATER_BUTTON_MAC && ctx.trigger.field === 'online' && ctx.trigger.event === true) {
      const remoteSwitchConnected = await ctx.getState(REMOTE_SWITCH_MAC, 'system', 'online');
      if (remoteSwitchConnected === true) {
        ctx.log('Water button connected - remote switch online, turning light on');
        for (let i = 0; i < 2; i++) {
          await ctx.sendRPC(WATER_BUTTON_MAC, 'Light.Set', { id: 0, on: true, brightness: 95 });
          await sleep(200);
          await ctx.sendRPC(WATER_BUTTON_MAC, 'Light.Set', { id: 0, on: false, brightness: 0 });
          await sleep(200);
        }
        await setLight(ctx.sendRPC, ctx.trigger.mac, true, 95);
      } else {
        ctx.log('Water button connected - remote switch offline, keeping light off');
        await ctx.sendRPC(WATER_BUTTON_MAC, 'Light.Set', { id: 0, on: false, brightness: 0 });
      }
      return;
    }

    // Remote switch comes online
    if (ctx.trigger.mac === REMOTE_SWITCH_MAC && ctx.trigger.field === 'online' && ctx.trigger.event === true) {
      ctx.log('Remote switch connected - turning switch off, flashing light, then turning light on');
      await ctx.sendRPC(REMOTE_SWITCH_MAC, 'Switch.Set', { id: 0, on: false });
      for (let i = 0; i < 2; i++) {
        await ctx.sendRPC(WATER_BUTTON_MAC, 'Light.Set', { id: 0, on: true, brightness: 95 });
        await sleep(200);
        await ctx.sendRPC(WATER_BUTTON_MAC, 'Light.Set', { id: 0, on: false, brightness: 0 });
        await sleep(200);
      }
      await setLight(ctx.sendRPC, WATER_BUTTON_MAC, true, 95);
      return;
    }

    // Remote switch goes offline — turn light off and cancel any timer
    if (ctx.trigger.mac === REMOTE_SWITCH_MAC && ctx.trigger.field === 'online' && ctx.trigger.event === false) {
      ctx.log('Remote switch went offline - turning light off');
      await ctx.sendRPC(WATER_BUTTON_MAC, 'Light.Set', { id: 0, on: false, brightness: 0 });
      const state = getState(WATER_BUTTON_MAC);
      if (state.timer) { clearTimeout(state.timer); state.timer = null; }
      state.countMode = false;
      state.timerStartedAt = null;
      state.timerEndsAt = null;
      return;
    }

    if (ctx.trigger.field !== 'button') return;

    // Ignore button events if remote switch is offline
    const remoteSwitchOnline = await ctx.getState(REMOTE_SWITCH_MAC, 'system', 'online');
    if (remoteSwitchOnline !== true) {
      ctx.log('Button ignored - remote switch is offline');
      return;
    }

    // ── Button events ────────────────────────────────────────────────────

    const mac = ctx.trigger.mac;
    const state = getState(mac);

    ctx.log(`Event: ${ctx.trigger.event}, countMode: ${state.countMode}, storedDuration: ${state.storedDuration}ms`);

    if (ctx.trigger.event === 'btn_down') {
      const timerWasActive = state.timer !== null;

      if (state.timer) { clearTimeout(state.timer); state.timer = null; }
      state.timerStartedAt = null;
      state.timerEndsAt = null;

      if (state.countMode) {
        await setLight(ctx.sendRPC, mac, false, 0);
        const elapsed = Date.now() - state.countStart;
        state.storedDuration = elapsed;
        state.countMode = false;
        ctx.log(`Count mode ended. Stored duration: ${elapsed}ms`);

        ctx.updateStatus({
          storedDuration: state.storedDuration,
          countMode: false,
          timerActive: false,
          lastAction: 'Duration saved'
        });

        persistedState[mac] = { storedDuration: elapsed };
        saveState(persistedState);

        await setLight(ctx.sendRPC, mac, true, 95);

      } else if (timerWasActive) {
        ctx.log('Timer cancelled by button press. Turning light on.');
        await setLight(ctx.sendRPC, mac, true, 95);

        ctx.updateStatus({
          storedDuration: state.storedDuration,
          countMode: false,
          timerActive: false,
          lastAction: 'Timer cancelled'
        });

      } else {
        await setLight(ctx.sendRPC, mac, false, 0);
        ctx.log(`Light off. Will turn on in ${state.storedDuration}ms`);

        const updateStatus = ctx.updateStatus;
        updateStatus({
          storedDuration: state.storedDuration,
          countMode: false,
          timerActive: true,
          lastAction: 'Timer started'
        });

        state.timerStartedAt = Date.now();
        state.timerEndsAt = Date.now() + state.storedDuration;

        state.timer = setTimeout(async () => {
          ctx.log('Timer elapsed. Turning light on.');
          const rpc = global.__waterBotRPC;
          if (rpc) await setLight(rpc, mac, true, 95);
          state.timer = null;
          state.timerStartedAt = null;
          state.timerEndsAt = null;

          updateStatus({
            storedDuration: state.storedDuration,
            countMode: false,
            timerActive: false,
            lastAction: 'Timer completed'
          });
        }, state.storedDuration);
      }
    }

    // long_push — enter count mode
    if (ctx.trigger.event === 'long_push' && !state.countMode) {
      if (state.timer) { clearTimeout(state.timer); state.timer = null; }
      state.timerStartedAt = null;
      state.timerEndsAt = null;

      ctx.log('Entering count mode...');

      for (let i = 0; i < 2; i++) {
        await ctx.sendRPC(mac, 'Light.Set', { id: 0, on: true, brightness: 95 });
        await sleep(200);
        await ctx.sendRPC(mac, 'Light.Set', { id: 0, on: false, brightness: 0 });
        await sleep(200);
      }

      await setLight(ctx.sendRPC, mac, false, 0);

      state.countMode = true;
      state.countStart = Date.now();
      ctx.log('Count mode active. Light stays off. Press button to set duration and turn on.');

      ctx.updateStatus({
        storedDuration: state.storedDuration,
        countMode: true,
        timerActive: false,
        lastAction: 'Counting...'
      });
    }
  }
};

// ── HTTP Status Page ──────────────────────────────────────────────────────────

startStatusServer({
  getState,
  WATER_BUTTON_MAC,
  REMOTE_SWITCH_MAC,
  setLight,
  persistedState,
  saveState
});
