# source: https://raw.githubusercontent.com/GGeronik/n170-verify/9e408b26b11d0d85be93bf2aa50c0774f735b48c/verify_toolkit/synthetic.py
# directory_url: https://github.com/GGeronik/n170-verify/blob/main/verify_toolkit/
# User: GGeronik
# Repository: n170-verify
# --------------------"""Original synthetic inputs for offline engineering checks, not market performance."""

from __future__ import annotations

import json
import math
from pathlib import Path


STRATEGIES = {
    "N170Clean": False,
    "N170Biased": True,
}


def build_config(request: dict) -> dict:
    """Build a deliberately narrow, credential-free spot backtest configuration."""
    return {
        "max_open_trades": 1,
        "stake_currency": "USDT",
        "stake_amount": 10000,
        "tradable_balance_ratio": 1.0,
        "dry_run": True,
        "dry_run_wallet": 1000000000,
        "trading_mode": "spot",
        "timeframe": request.get("timeframe", "5m"),
        "timerange": request.get("timerange", "20260101-20260104"),
        "fee": request.get("fee", 0.001),
        "dataformat_ohlcv": "json",
        "exchange": {
            "name": "binance",
            "pair_whitelist": ["BTC/USDT"],
            "pair_blacklist": [],
            "enable_ws": False,
        },
        "pairlists": [{"method": "StaticPairList"}],
        "entry_pricing": {"price_side": "other", "use_order_book": False},
        "exit_pricing": {"price_side": "other", "use_order_book": False},
        "unfilledtimeout": {"entry": 10, "exit": 10, "unit": "minutes"},
        "cancel_open_orders_on_exit": False,
        "bot_name": "n170-offline-synthetic",
        "initial_state": "stopped",
    }


def strategy_source(name: str, *, biased: bool = False, never: bool = False, fail: bool = False) -> str:
    """Return original, transparent periodic strategies with an optional future column."""
    indicator = (
        '        dataframe["future_close"] = dataframe["close"].shift(-1)\n'
        if biased else
        '        dataframe["past_mean"] = dataframe["close"].rolling(3).mean()\n'
    )
    if fail:
        indicator = '        raise RuntimeError("Original deliberate failure control")\n'
    entry_condition = ('dataframe["volume"] < 0' if never else
                       '(dataframe["date"].dt.minute % 30 == 0) & (dataframe["volume"] > 0)')
    return (
        '# Original N170 synthetic engineering fixture. SPDX-License-Identifier: Apache-2.0\n'
        '# This is not a financial strategy or real-market performance evidence.\n'
        'from freqtrade.strategy import IStrategy\n\n\n'
        f'class Github_GGeronik_n170_verify__synthetic__20261102_224143(IStrategy):\n'
        '    INTERFACE_VERSION = 3\n'
        '    timeframe = "5m"\n'
        '    startup_candle_count = 3\n'
        '    minimal_roi = {"0": 100.0}\n'
        '    stoploss = -0.99\n'
        '    can_short = False\n'
        '    def populate_indicators(self, dataframe, metadata):\n'
        + indicator +
        '        return dataframe\n\n'
        '    def populate_entry_trend(self, dataframe, metadata):\n'
        f'        dataframe.loc[{entry_condition}, "enter_long"] = 1\n'
        '        return dataframe\n\n'
        '    def populate_exit_trend(self, dataframe, metadata):\n'
        '        dataframe.loc[dataframe["date"].dt.minute % 30 == 10, "exit_long"] = 1\n'
        '        return dataframe\n'
    )


def generate_fixture(destination: str | Path) -> Path:
    """Create a new fixture directory exclusively; never reuse stale fixture files."""
    destination = Path(destination)
    destination.mkdir(parents=True, exist_ok=False)
    (destination / "data").mkdir()
    (destination / "strategies").mkdir()
    # Three days of original deterministic five-minute OHLCV plus startup candles.
    start_ms = 1767225600000 - 12 * 300000
    candles = []
    for index in range(3 * 24 * 12 + 12):
        opening = 100 + 2 * math.sin(index / 13) + 0.2 * math.cos(index / 7)
        closing = opening + 0.1 * math.sin(index / 3)
        candles.append([
            start_ms + index * 300000,
            round(opening, 8), round(max(opening, closing) + 0.25, 8),
            round(min(opening, closing) - 0.25, 8), round(closing, 8),
            round(1000 + index % 29, 8),
        ])
    (destination / "data" / "BTC_USDT-5m.json").write_text(
        json.dumps(candles, separators=(",", ":")) + "\n", encoding="utf-8"
    )
    (destination / "config.json").write_text(
        json.dumps(build_config({}), indent=2, sort_keys=True) + "\n", encoding="utf-8"
    )
    for name, biased in STRATEGIES.items():
        (destination / "strategies" / f"Github_GGeronik_n170_verify__synthetic__20261102_224143.py").write_text(
            strategy_source(name, biased=biased), encoding="utf-8"
        )
    for name, flags in [("N170Never", {"never": True}), ("N170Failure", {"fail": True})]:
        (destination / "strategies" / f"Github_GGeronik_n170_verify__synthetic__20261102_224143.py").write_text(
            strategy_source(name, **flags), encoding="utf-8"
        )
    (destination / "SCOPE.txt").write_text(
        "Original deterministic synthetic market data and benign local strategies.\n"
        "Engineering controls only; no real-market strategy performance claim.\n"
        "N170Biased deliberately reads the following candle using shift(-1).\n",
        encoding="utf-8",
    )
    return destination
