# source: https://raw.githubusercontent.com/dasein108/freqtrade_dev_mcp/262451b7d87d8bab6404dddba28a78b7f11879da/src/commands/create_strategy_wireframe.py
# directory_url: https://github.com/dasein108/freqtrade_dev_mcp/blob/dev/src/commands/
# User: dasein108
# Repository: freqtrade_dev_mcp
# --------------------"""Create strategy wireframe command implementation."""

import logging
from pathlib import Path
from typing import Any, Dict, Optional

try:
    from .base import BaseCommand, validate_strategy_name
except ImportError:
    import sys
    from pathlib import Path

    sys.path.insert(0, str(Path(__file__).parent.parent))
    from commands.base import BaseCommand, validate_strategy_name

logger = logging.getLogger(__name__)


class CreateStrategyWireframeCommand(BaseCommand):
    """Command to create minimal strategy wireframes for maximum LLM flexibility."""

    async def execute(
        self,
        strategy_name: str,
        strategy_path: Optional[str] = None,
        style: str = "minimal",  # minimal, guided, structured
        include_comments: bool = True,
        include_examples: bool = False,
        description: Optional[str] = None,
        **kwargs,
    ) -> Dict[str, Any]:
        """Execute create strategy wireframe command.

        Args:
            strategy_name: Name of the strategy class and file
            strategy_path: Custom path for strategy file (optional)
            style: Wireframe style (minimal, guided, structured)
            include_comments: Include TODO comments and guidance
            include_examples: Include example code snippets
            description: Strategy description to include in docstring

        Returns:
            Command execution result with created wireframe details
        """
        try:
            await self.mcp_log("info", f"Creating strategy wireframe: Github_dasein108_freqtrade_dev_mcp__create_strategy_wireframe__20260922_210314")

            validate_strategy_name(strategy_name)

            # Determine strategy file path (defaults to the configured strategies directory,
            # which is where backtest/hyperopt look for strategies)
            if strategy_path:
                strategy_file_path = self.resolve_workspace_path(strategy_path)
                if strategy_file_path.suffix != ".py":
                    raise ValueError("strategy_path must point to a .py file")
            else:
                strategies_dir = self.config.full_strategy_dir
                strategies_dir.mkdir(parents=True, exist_ok=True)
                strategy_file_path = strategies_dir / f"Github_dasein108_freqtrade_dev_mcp__create_strategy_wireframe__20260922_210314.py"

            # Check if file already exists
            if strategy_file_path.exists():
                return {
                    "command": "create_strategy_wireframe",
                    "success": False,
                    "error": f"Strategy file {strategy_file_path} already exists. Remove it first or use a different name.",
                    "strategy_path": str(strategy_file_path),
                }

            # Generate wireframe code
            wireframe_code = self._generate_wireframe_code(
                strategy_name=strategy_name,
                style=style,
                include_comments=include_comments,
                include_examples=include_examples,
                description=description,
            )

            # Create directory if it doesn't exist
            strategy_file_path.parent.mkdir(parents=True, exist_ok=True)

            # Write wireframe to file
            strategy_file_path.write_text(wireframe_code)

            await self.mcp_log(
                "info", f"Strategy wireframe created successfully at {strategy_file_path}"
            )

            return {
                "command": "create_strategy_wireframe",
                "success": True,
                "strategy_name": strategy_name,
                "strategy_path": str(strategy_file_path),
                "style": style,
                "wireframe_info": {
                    "lines_of_code": len(wireframe_code.split("\n")),
                    "includes_comments": include_comments,
                    "includes_examples": include_examples,
                    "ready_for_customization": True,
                },
                "next_steps": [
                    "Customize populate_indicators() with your technical indicators",
                    "Define entry logic in populate_entry_trend()",
                    "Define exit logic in populate_exit_trend()",
                    "Adjust strategy parameters (ROI, stoploss, timeframe)",
                    "Test with backtesting and optimize with hyperopt",
                ],
            }

        except Exception as e:
            await self.mcp_log("error", f"Create strategy wireframe command failed: {e}")
            return {
                "command": "create_strategy_wireframe",
                "success": False,
                "error": str(e),
                "strategy_name": strategy_name,
            }

    def _generate_wireframe_code(
        self,
        strategy_name: str,
        style: str,
        include_comments: bool,
        include_examples: bool,
        description: Optional[str],
    ) -> str:
        """Generate wireframe code based on style and options."""

        if style == "minimal":
            return self._generate_minimal_wireframe(strategy_name, description, include_comments)
        elif style == "guided":
            return self._generate_guided_wireframe(
                strategy_name, description, include_comments, include_examples
            )
        elif style == "structured":
            return self._generate_structured_wireframe(
                strategy_name, description, include_comments, include_examples
            )
        else:
            return self._generate_minimal_wireframe(strategy_name, description, include_comments)

    def _generate_minimal_wireframe(
        self, strategy_name: str, description: Optional[str], include_comments: bool
    ) -> str:
        """Generate minimal wireframe - maximum flexibility for LLMs."""

        desc = description or f"TODO: Describe your Github_dasein108_freqtrade_dev_mcp__create_strategy_wireframe__20260922_210314 strategy"

        comments = {
            "class_comment": (
                f'''
    \"\"\"
    {desc}

    TODO: Implement your trading strategy logic
    \"\"\"'''
                if include_comments
                else ""
            ),
            "indicators_comment": (
                '''
        """
        TODO: Add your technical indicators here
        Examples: RSI, MACD, Bollinger Bands, Moving Averages, etc.
        """'''
                if include_comments
                else ""
            ),
            "entry_comment": (
                '''
        """
        TODO: Define your entry conditions
        Combine indicators and market conditions to create entry signals
        """'''
                if include_comments
                else ""
            ),
            "exit_comment": (
                '''
        """
        TODO: Define your exit conditions
        Set conditions for taking profits or cutting losses
        """'''
                if include_comments
                else ""
            ),
        }

        return f'''\
"""Github_dasein108_freqtrade_dev_mcp__create_strategy_wireframe__20260922_210314 Strategy

{desc}

Generated wireframe - customize as needed.
"""

from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
import talib.abstract as ta


class Github_dasein108_freqtrade_dev_mcp__create_strategy_wireframe__20260922_210314(IStrategy):{comments["class_comment"]}

    # Strategy interface version
    INTERFACE_VERSION: int = 3

    # TODO: Set your preferred timeframe
    timeframe = '5m'

    # TODO: Enable if strategy can short
    can_short: bool = False

    # TODO: Define your ROI table
    minimal_roi = {{
        "60": 0.01,
        "30": 0.02,
        "0": 0.04
    }}

    # TODO: Set your stop loss
    stoploss = -0.10

    # TODO: Configure trailing stop if needed
    trailing_stop = False

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:{comments["indicators_comment"]}
        # TODO: Add your indicators here

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:{comments["entry_comment"]}
        # TODO: Define entry conditions
        # Example structure:
        # dataframe.loc[
        #     (
        #         # Your conditions here
        #         (dataframe['volume'] > 0)  # Always include volume check
        #     ),
        #     'enter_long'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:{comments["exit_comment"]}
        # TODO: Define exit conditions
        # Example structure:
        # dataframe.loc[
        #     (
        #         # Your exit conditions here
        #         (dataframe['volume'] > 0)  # Always include volume check
        #     ),
        #     'exit_long'] = 1

        return dataframe
'''

    def _generate_guided_wireframe(
        self,
        strategy_name: str,
        description: Optional[str],
        include_comments: bool,
        include_examples: bool,
    ) -> str:
        """Generate guided wireframe with more hints and examples."""

        desc = description or f"Guided wireframe for Github_dasein108_freqtrade_dev_mcp__create_strategy_wireframe__20260922_210314 strategy"

        examples = (
            """
        # Example indicators - uncomment and modify as needed:
        # dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        # dataframe['macd'] = ta.MACD(dataframe)['macd']
        # dataframe['bb_lower'] = ta.BBANDS(dataframe)['lowerband']
        # dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20)
        # dataframe['ema12'] = ta.EMA(dataframe, timeperiod=12)
        """
            if include_examples
            else ""
        )

        entry_examples = (
            """
        # Example entry conditions - uncomment and modify:
        # dataframe.loc[
        #     (
        #         (dataframe['rsi'] < 30) &          # Oversold
        #         (dataframe['close'] > dataframe['sma20']) &  # Above trend
        #         (dataframe['volume'] > dataframe['volume'].rolling(20).mean()) &  # High volume
        #         (dataframe['volume'] > 0)           # Volume check
        #     ),
        #     'enter_long'] = 1
        """
            if include_examples
            else ""
        )

        exit_examples = (
            """
        # Example exit conditions - uncomment and modify:
        # dataframe.loc[
        #     (
        #         (dataframe['rsi'] > 70) |          # Overbought
        #         (dataframe['close'] < dataframe['sma20']) |  # Below trend
        #         (dataframe['volume'] > 0)           # Volume check
        #     ),
        #     'exit_long'] = 1
        """
            if include_examples
            else ""
        )

        return f'''\
"""Github_dasein108_freqtrade_dev_mcp__create_strategy_wireframe__20260922_210314 Strategy

{desc}

This guided wireframe provides structure and examples to help you build your strategy.
Follow the TODO comments and uncomment/modify example code as needed.
"""

from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
import talib.abstract as ta
import numpy as np


class Github_dasein108_freqtrade_dev_mcp__create_strategy_wireframe__20260922_210314(IStrategy):
    """
    Guided strategy wireframe with examples and hints.

    Step 1: Choose your indicators in populate_indicators()
    Step 2: Define entry logic in populate_entry_trend()
    Step 3: Define exit logic in populate_exit_trend()
    Step 4: Tune parameters (ROI, stoploss, etc.)
    Step 5: Backtest and optimize
    """

    # Strategy interface version - always use 3
    INTERFACE_VERSION: int = 3

    # TODO: Choose optimal timeframe for your strategy
    # Common: '1m', '5m', '15m', '1h', '4h', '1d'
    timeframe = '5m'

    # TODO: Set to True if strategy can go short
    can_short: bool = False

    # TODO: Define ROI table - profits at which to exit
    # Format: "minutes": profit_ratio
    minimal_roi = {{
        "60": 0.01,    # 1% after 60 minutes
        "30": 0.02,    # 2% after 30 minutes
        "0": 0.04      # 4% immediately
    }}

    # TODO: Set stop loss (negative value, e.g., -0.10 = 10% loss)
    stoploss = -0.10

    # TODO: Enable trailing stop to lock in profits
    trailing_stop = False
    # trailing_stop_positive = 0.01
    # trailing_stop_positive_offset = 0.02

    # TODO: Add strategy-specific parameters for optimization
    # buy_rsi = IntParameter(20, 40, default=30, space="buy")
    # sell_rsi = IntParameter(60, 80, default=70, space="sell")

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Add technical indicators to the dataframe.

        This is where you calculate all the indicators you'll use in your entry/exit logic.
        Common indicators: RSI, MACD, Bollinger Bands, Moving Averages, Volume indicators
        """

        # TODO: Add your indicators here{examples}

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Define entry signals for your strategy.

        Set 'enter_long' = 1 where you want to enter long positions.
        Set 'enter_short' = 1 where you want to enter short positions (if can_short=True).

        Combine multiple indicators for better signals.
        Always include volume > 0 check.
        """

        # TODO: Define your entry conditions{entry_examples}

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Define exit signals for your strategy.

        Set 'exit_long' = 1 where you want to exit long positions.
        Set 'exit_short' = 1 where you want to exit short positions.

        Note: ROI and stoploss will also trigger exits automatically.
        """

        # TODO: Define your exit conditions{exit_examples}

        return dataframe

    # TODO: Uncomment and implement custom methods if needed
    # def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
    #                     current_rate: float, current_profit: float, **kwargs) -> float:
    #     """Custom stoploss logic"""
    #     return self.stoploss

    # def confirm_trade_entry(self, pair: str, order_type: str, amount: float,
    #                         rate: float, time_in_force: str, current_time: datetime,
    #                         entry_tag: Optional[str], side: str, **kwargs) -> bool:
    #     """Confirm trade entry"""
    #     return True
'''

    def _generate_structured_wireframe(
        self,
        strategy_name: str,
        description: Optional[str],
        include_comments: bool,
        include_examples: bool,
    ) -> str:
        """Generate structured wireframe with organized sections and advanced features."""

        desc = (
            description
            or f"Structured wireframe for Github_dasein108_freqtrade_dev_mcp__create_strategy_wireframe__20260922_210314 strategy with advanced features"
        )

        return f'''\
"""Github_dasein108_freqtrade_dev_mcp__create_strategy_wireframe__20260922_210314 Strategy

{desc}

This structured wireframe provides a comprehensive template with organized sections
for building sophisticated trading strategies.
"""

from freqtrade.strategy.interface import IStrategy
from freqtrade.strategy import merge_informative_pair, DecimalParameter, IntParameter, BooleanParameter
from pandas import DataFrame
import talib.abstract as ta
import numpy as np
from typing import Optional
from datetime import datetime


class Github_dasein108_freqtrade_dev_mcp__create_strategy_wireframe__20260922_210314(IStrategy):
    """
    Structured strategy template with advanced features.

    Features included:
    - Hyperopt parameter optimization
    - Informative timeframes
    - Custom stoploss and ROI
    - Entry/exit confirmation
    - Risk management
    """

    # Strategy interface version
    INTERFACE_VERSION: int = 3

    # === BASIC CONFIGURATION ===
    timeframe = '5m'
    can_short: bool = False

    # Startup candle count for indicators
    startup_candle_count: int = 30

    # === ROI & STOPLOSS ===
    minimal_roi = {{
        "60": 0.01,
        "30": 0.02,
        "0": 0.04
    }}

    stoploss = -0.10
    trailing_stop = False

    # === HYPEROPT PARAMETERS ===
    # TODO: Define parameters for optimization
    # buy_rsi_enabled = BooleanParameter(default=True, space="buy")
    # buy_rsi = IntParameter(20, 40, default=30, space="buy")
    # sell_rsi = IntParameter(60, 80, default=70, space="sell")
    # roi_p1 = DecimalParameter(0.01, 0.05, default=0.01, space="sell")
    # roi_p2 = DecimalParameter(0.01, 0.07, default=0.02, space="sell")
    # roi_p3 = DecimalParameter(0.01, 0.20, default=0.04, space="sell")

    # === INFORMATIVE TIMEFRAMES ===
    def informative_pairs(self):
        """
        Define additional pairs and timeframes for context.
        """
        pairs = self.dp.current_whitelist()
        informative_pairs = []

        # TODO: Add informative timeframes
        # for pair in pairs:
        #     informative_pairs.append((pair, '1h'))

        return informative_pairs

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Add technical indicators organized by category.
        """

        # === TREND INDICATORS ===
        # TODO: Add trend indicators
        # dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20)
        # dataframe['ema12'] = ta.EMA(dataframe, timeperiod=12)
        # dataframe['ema26'] = ta.EMA(dataframe, timeperiod=26)

        # === MOMENTUM INDICATORS ===
        # TODO: Add momentum indicators
        # dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        # macd = ta.MACD(dataframe)
        # dataframe['macd'] = macd['macd']
        # dataframe['macdsignal'] = macd['macdsignal']

        # === VOLATILITY INDICATORS ===
        # TODO: Add volatility indicators
        # bollinger = ta.BBANDS(dataframe, timeperiod=20)
        # dataframe['bb_lower'] = bollinger['lowerband']
        # dataframe['bb_middle'] = bollinger['middleband']
        # dataframe['bb_upper'] = bollinger['upperband']
        # dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)

        # === VOLUME INDICATORS ===
        # TODO: Add volume indicators
        # dataframe['volume_sma'] = ta.SMA(dataframe['volume'], timeperiod=20)

        # === INFORMATIVE TIMEFRAME DATA ===
        # TODO: Merge informative timeframe data
        # if self.dp:
        #     inf_tf = '1h'
        #     informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=inf_tf)
        #     informative['rsi_1h'] = ta.RSI(informative, timeperiod=14)
        #     dataframe = merge_informative_pair(dataframe, informative, self.timeframe, inf_tf, ffill=True)

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Define entry conditions with organized logic.
        """

        conditions_long = []
        conditions_short = []

        # === LONG ENTRY CONDITIONS ===
        # TODO: Add long entry conditions
        # Trend conditions
        # conditions_long.append(dataframe['close'] > dataframe['sma20'])

        # Momentum conditions
        # conditions_long.append(dataframe['rsi'] < self.buy_rsi.value)

        # Volume conditions
        # conditions_long.append(dataframe['volume'] > dataframe['volume_sma'])

        # Volatility conditions
        # conditions_long.append(dataframe['close'] < dataframe['bb_lower'])

        # Base conditions (always required)
        conditions_long.append(dataframe['volume'] > 0)

        # === SHORT ENTRY CONDITIONS ===
        if self.can_short:
            # TODO: Add short entry conditions
            # conditions_short.append(dataframe['close'] < dataframe['sma20'])
            # conditions_short.append(dataframe['rsi'] > 70)
            conditions_short.append(dataframe['volume'] > 0)

        # Apply conditions
        if conditions_long:
            dataframe.loc[
                reduce(lambda x, y: x & y, conditions_long),
                'enter_long'
            ] = 1

        if conditions_short:
            dataframe.loc[
                reduce(lambda x, y: x & y, conditions_short),
                'enter_short'
            ] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Define exit conditions with organized logic.
        """

        conditions_long_exit = []
        conditions_short_exit = []

        # === LONG EXIT CONDITIONS ===
        # TODO: Add long exit conditions
        # conditions_long_exit.append(dataframe['rsi'] > self.sell_rsi.value)
        # conditions_long_exit.append(dataframe['close'] > dataframe['bb_upper'])

        # Base conditions
        conditions_long_exit.append(dataframe['volume'] > 0)

        # === SHORT EXIT CONDITIONS ===
        if self.can_short:
            # TODO: Add short exit conditions
            # conditions_short_exit.append(dataframe['rsi'] < 30)
            conditions_short_exit.append(dataframe['volume'] > 0)

        # Apply conditions
        if conditions_long_exit:
            dataframe.loc[
                reduce(lambda x, y: x & y, conditions_long_exit),
                'exit_long'
            ] = 1

        if conditions_short_exit:
            dataframe.loc[
                reduce(lambda x, y: x & y, conditions_short_exit),
                'exit_short'
            ] = 1

        return dataframe

    # === CUSTOM METHODS ===

    def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
                       current_rate: float, current_profit: float, **kwargs) -> float:
        """
        Custom stoploss logic - TODO: Implement if needed
        """
        # TODO: Implement custom stoploss logic
        # Example: Trailing stoploss that becomes more aggressive over time
        return self.stoploss

    def confirm_trade_entry(self, pair: str, order_type: str, amount: float,
                           rate: float, time_in_force: str, current_time: datetime,
                           entry_tag: Optional[str], side: str, **kwargs) -> bool:
        """
        Entry confirmation - TODO: Implement if needed
        """
        # TODO: Add entry confirmation logic
        # Example: Check for sufficient volume, spread, etc.
        return True

    def confirm_trade_exit(self, pair: str, trade: 'Trade', order_type: str,
                          amount: float, rate: float, time_in_force: str,
                          exit_reason: str, current_time: datetime, **kwargs) -> bool:
        """
        Exit confirmation - TODO: Implement if needed
        """
        # TODO: Add exit confirmation logic
        return True

    # === HELPER METHODS ===

    def get_market_condition(self, dataframe: DataFrame) -> str:
        """
        Determine market condition - TODO: Implement if needed
        """
        # TODO: Implement market condition detection
        # Example: trending, ranging, volatile
        return "unknown"


# TODO: Import reduce function if using conditions
from functools import reduce
'''
