"""
core/candle_logger.py — M1-Candle-Logger (Daten-Sammlung, KEIN Strategie-Eingriff)
==================================================================================
Schreibt **abgeschlossene** M1-Kerzen (OHLC + Spread + Tick-Volumen) in eine eigene
SQLite-Tabelle, damit über die Zeit ein tiefer M1-Datensatz entsteht — die
Broker-M1-History ist kurz und rollt weg. M1 ist die Master-Auflösung: daraus lässt
sich jede höhere TF (M5/M15/M30/H1) exakt aggregieren.

Zeitbasis: `time` = ROHE MT5-Bar-Zeit (**Broker/UTC+3**), wie `copy_rates_from_pos`
sie liefert — deckungsgleich mit allen Backtests. Nur ABGESCHLOSSENE Bars (die letzte,
noch offene Kerze wird nie geschrieben). Idempotent via PRIMARY KEY + INSERT OR IGNORE,
self-healing (jeder Fetch backfillt die letzten N Bars).
"""
from __future__ import annotations
import sqlite3
import threading
import time

import MetaTrader5 as mt5

from core.mt5_utils import mt5_lock
from core.logger import get_logger

log = get_logger("candles")

_REFRESH_S = 55.0     # M1 ändert sich je 60 s → ~55-s-Takt (kein Sub-Minuten-Fetch)
_FETCH_N   = 180      # je Fetch die letzten N M1-Bars (backfillt Lücken bis ~3 h)
_STARTUP_N = 3000     # erster Lauf: tiefer holen (~2 Handelstage Backfill nach Restart)


class CandleLogger:
    def __init__(self, db_path: str):
        self.db_path = db_path
        self._last = 0.0
        self._first = True
        self._lock = threading.Lock()
        self._ensure()

    def _ensure(self):
        try:
            con = sqlite3.connect(self.db_path, timeout=5.0)
            con.execute("""CREATE TABLE IF NOT EXISTS candles_m1 (
                time        INTEGER PRIMARY KEY,   -- Broker-Epoch (UTC+3), rohe MT5-Bar-Zeit
                o REAL, h REAL, l REAL, c REAL,
                spread      REAL,                  -- in Preis (spread_points × point)
                tick_volume INTEGER,
                symbol      TEXT )""")
            con.commit(); con.close()
        except Exception as e:
            log.warning(f"candles_m1 anlegen: {e}")

    def log(self, sym: str):
        """Im Trend-Loop aufgerufen; self-throttled auf ~55 s. Holt die letzten N
        M1-Bars und schreibt die abgeschlossenen (INSERT OR IGNORE = dedupliziert)."""
        if not sym:
            return
        now = time.time()
        with self._lock:
            if now - self._last < _REFRESH_S:
                return
            n = _STARTUP_N if self._first else _FETCH_N
        try:
            with mt5_lock(timeout=2) as got:
                if not got:
                    return
                bars = mt5.copy_rates_from_pos(sym, mt5.TIMEFRAME_M1, 0, n)
                si = mt5.symbol_info(sym); point = si.point if si else 0.01
            if bars is None or len(bars) < 2:
                return
            # letzte Bar ist noch OFFEN → weglassen (nur abgeschlossene schreiben)
            rows = [(int(b["time"]), float(b["open"]), float(b["high"]), float(b["low"]),
                     float(b["close"]), round(float(b["spread"]) * point, 5),
                     int(b["tick_volume"]), sym) for b in bars[:-1]]
            con = sqlite3.connect(self.db_path, timeout=5.0)
            before = con.execute("SELECT COUNT(*) FROM candles_m1").fetchone()[0]
            con.executemany(
                "INSERT OR IGNORE INTO candles_m1 (time,o,h,l,c,spread,tick_volume,symbol) "
                "VALUES (?,?,?,?,?,?,?,?)", rows)
            con.commit()
            ins = con.execute("SELECT COUNT(*) FROM candles_m1").fetchone()[0] - before
            con.close()
            with self._lock:
                self._last = now
                was_first = self._first
                self._first = False
            if was_first:
                log.info(f"M1-Candle-Logger: Start-Backfill +{ins} Bars ({sym})")
            elif ins > 0:
                log.debug(f"M1-Candles: +{ins}")
        except Exception as e:
            log.warning(f"candle log: {e}")

    def stats(self) -> dict:
        try:
            con = sqlite3.connect(self.db_path, timeout=5.0)
            r = con.execute("SELECT COUNT(*), MIN(time), MAX(time) FROM candles_m1").fetchone()
            con.close()
            return {"n": r[0] or 0, "first": r[1], "last": r[2]}
        except Exception:
            return {"n": 0}
