# source: https://raw.githubusercontent.com/cuongccna/tracetradelab/78d5339eb8ca654dcff00e68a783dcd6a6a34936/repo/freqtrade/user_data/strategies/AISignalStrategy.py
"""Freqtrade long-only strategy driven by the external TradingAgents signal DB."""

from __future__ import annotations

import logging
import os
import sqlite3
from datetime import datetime, timezone
from pathlib import Path

import pandas as pd
from freqtrade.strategy import IStrategy


log = logging.getLogger(__name__)
DB_PATH = Path(os.getenv("SIGNAL_DB_PATH", "/bridge/signals.db"))
MIN_CONFIDENCE = float(os.getenv("TRACE_MIN_CONFIDENCE", "0.65"))


def _signal_symbol(pair: str) -> str:
    return pair.split(":", 1)[0]


def _read_signal(symbol: str) -> dict | None:
    if not DB_PATH.exists():
        log.warning("Signal database not found at %s", DB_PATH)
        return None
    try:
        uri = f"{DB_PATH.resolve().as_uri()}?mode=ro"
        with sqlite3.connect(uri, uri=True, timeout=5) as conn:
            row = conn.execute(
                """
                SELECT action, confidence, stop_loss, reason, created_at
                FROM signals
                WHERE symbol = ? AND expires_at > ?
                ORDER BY created_at DESC
                LIMIT 1
                """,
                (symbol, datetime.now(timezone.utc).isoformat()),
            ).fetchone()
    except sqlite3.Error as exc:
        log.error("Unable to read signal database: %s", exc)
        return None
    if row is None:
        return None
    return {
        "action": row[0],
        "confidence": row[1],
        "stop_loss": row[2],
        "reason": row[3] or "",
        "created_at": row[4],
    }


class Github_cuongccna_tracetradelab__AISignalStrategy__20260602_152139(IStrategy):
    """Execute only fresh high-conviction long entries during dry-run."""

    INTERFACE_VERSION = 3
    timeframe = "4h"
    can_short = False

    minimal_roi = {"0": 0.04, "720": 0.025, "1440": 0.015}
    stoploss = -0.025
    use_custom_stoploss = True
    trailing_stop = False
    process_only_new_candles = True
    use_exit_signal = True
    exit_profit_only = False
    startup_candle_count = 20

    def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        return dataframe

    def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        dataframe["enter_long"] = 0
        dataframe["enter_tag"] = ""
        if dataframe.empty:
            return dataframe

        signal = _read_signal(_signal_symbol(metadata["pair"]))
        if signal and signal["action"] == "BUY" and signal["confidence"] >= MIN_CONFIDENCE:
            # Filter: dead zone 22:00–01:00 UTC (volume thấp, spread rộng)
            last_ts = dataframe.index[-1]
            if hasattr(last_ts, "hour") and last_ts.hour in {22, 23, 0, 1}:
                log.debug("%s: skipping BUY — dead zone hour %d UTC", metadata["pair"], last_ts.hour)
                return dataframe

            # Filter: volume bất thường thấp (< 50% trung bình 20 candle)
            vol_mean = dataframe["volume"].iloc[-20:].mean()
            if vol_mean > 0 and dataframe["volume"].iloc[-1] < 0.5 * vol_mean:
                log.debug("%s: skipping BUY — volume too low (ratio %.2f)", metadata["pair"],
                          dataframe["volume"].iloc[-1] / vol_mean)
                return dataframe

            dataframe.loc[dataframe.index[-1], "enter_long"] = 1
            dataframe.loc[dataframe.index[-1], "enter_tag"] = (
                f"AI_BUY_{signal['confidence']:.2f}"
            )
            log.info("%s: entry from AI signal (%0.2f)", metadata["pair"], signal["confidence"])
        return dataframe

    def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
        dataframe["exit_long"] = 0
        dataframe["exit_tag"] = ""
        if dataframe.empty:
            return dataframe

        signal = _read_signal(_signal_symbol(metadata["pair"]))
        if signal is None:
            dataframe.loc[dataframe.index[-1], "exit_long"] = 1
            dataframe.loc[dataframe.index[-1], "exit_tag"] = "STALE_SIGNAL"
        elif signal["action"] in ("SELL", "EXIT"):
            dataframe.loc[dataframe.index[-1], "exit_long"] = 1
            dataframe.loc[dataframe.index[-1], "exit_tag"] = (
                f"AI_{signal['action']}_{signal['confidence']:.2f}"
            )
        return dataframe

    def custom_exit(
        self,
        pair: str,
        trade,
        current_time: datetime,
        current_rate: float,
        current_profit: float,
        **kwargs,
    ) -> str | None:
        """Apply safety exits as soon as a new AI signal is stored."""
        signal = _read_signal(_signal_symbol(pair))
        if signal is None:
            return "STALE_SIGNAL"
        if signal["action"] in ("SELL", "EXIT"):
            return f"AI_{signal['action']}_{signal['confidence']:.2f}"
        return None

    def custom_stoploss(
        self,
        pair: str,
        trade,
        current_time: datetime,
        current_rate: float,
        current_profit: float,
        after_fill: bool,
        **kwargs,
    ) -> float | None:
        signal = _read_signal(_signal_symbol(pair))
        if signal and signal["stop_loss"] is not None:
            return -min(abs(signal["stop_loss"]), 0.03)
        return None
