import { StateGraph } from '@langchain/langgraph';
import { BaseWorkflow, type WorkflowConfig } from '../base-workflow.js';
import { TradingRequestState, type TradingRequestStateType } from './state.js';
import type { FastifyBaseLogger } from 'fastify';
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { HumanMessage, SystemMessage } from '@langchain/core/messages';

/**
 * Trading Request Workflow
 *
 * Human-in-the-loop workflow for executing trades:
 * 1. Analyze market conditions
 * 2. Calculate risk and position size
 * 3. Request human approval (PAUSE HERE)
 * 4. If approved → Execute trade
 * 5. Generate execution summary
 *
 * Features:
 * - Interrupt at approval node
 * - Resume with user input
 * - Risk validation
 * - Multi-channel approval UI
 */
export class TradingRequestWorkflow extends BaseWorkflow<TradingRequestStateType> {
  constructor(
    config: WorkflowConfig,
    private model: BaseChatModel,
    private marketDataFn: (ticker: string) => Promise<{ price: number; [key: string]: unknown }>,
    private executeTradeFn: (order: any) => Promise<{ orderId: string; status: string; price: number }>,
    logger: FastifyBaseLogger
  ) {
    super(config, logger);
  }

  buildGraph(): any {
    const graph = new StateGraph(TradingRequestState);

    // Node: Analyze market
    const analyzeNode = async (state: TradingRequestStateType): Promise<Partial<TradingRequestStateType>> => {
      this.logger.info('Trading request: Analyzing market');

      const marketData = await this.marketDataFn(state.ticker);

      const systemPrompt = `You are a market analyst. Analyze current conditions for a ${state.side} order.`;
      const userPrompt = `Ticker: ${state.ticker}
Current Price: ${marketData.price}
Requested: ${state.side} ${state.amount} at ${state.price || 'market'}

Provide 2-3 sentence analysis:`;

      const response = await this.model.invoke([
        new SystemMessage(systemPrompt),
        new HumanMessage(userPrompt),
      ]);

      return {
        marketAnalysis: response.content as string,
        currentPrice: marketData.price,
      };
    };

    // Node: Calculate risk
    const calculateRiskNode = async (state: TradingRequestStateType): Promise<Partial<TradingRequestStateType>> => {
      this.logger.info('Trading request: Calculating risk');

      // Simplified risk calculation
      const accountBalance = state.userContext.license.features.maxBacktestDays * 1000; // Mock
      const maxPosition = accountBalance * 0.05; // 5% max

      const positionValue = state.amount * (state.currentPrice || 0);
      const positionSize = Math.min(positionValue, maxPosition);

      // Mock risk/reward (in production, calculate from stop-loss and take-profit)
      const riskRewardRatio = 2.5;

      return {
        riskAssessment: {
          accountBalance,
          maxPosition,
          positionValue,
          positionSize,
        },
        riskRewardRatio,
        positionSize,
      };
    };

    // Node: Request approval (INTERRUPT POINT)
    const requestApprovalNode = async (state: TradingRequestStateType): Promise<Partial<TradingRequestStateType>> => {
      this.logger.info('Trading request: Requesting approval');

      // TODO: Send approval request to user's active channel
      // In production, this would:
      // 1. Format approval UI for the channel (buttons for Telegram, etc.)
      // 2. Send message with trade details
      // 3. Store workflow state
      // 4. Return with interrupt signal
      // 5. LangGraph will pause here until resumed with user input

      // For now, mock approval
      const approvalMessage = `
Trade Request Approval Needed:
- ${state.side.toUpperCase()} ${state.amount} ${state.ticker}
- Current Price: $${state.currentPrice}
- Position Size: $${state.positionSize}
- Risk/Reward: ${state.riskRewardRatio}:1

Market Analysis:
${state.marketAnalysis}

Reply 'approve' or 'reject'
`;

      return {
        approvalRequested: true,
        approvalMessage,
        approvalTimestamp: Date.now(),
        // In production, this node would use Interrupt here
        userApproved: false, // Wait for user input
      };
    };

    // Node: Execute trade
    const executeTradeNode = async (state: TradingRequestStateType): Promise<Partial<TradingRequestStateType>> => {
      this.logger.info('Trading request: Executing trade');

      try {
        const order = {
          ticker: state.ticker,
          side: state.side,
          amount: state.amount,
          type: state.requestType,
          price: state.price,
        };

        const result = await this.executeTradeFn(order);

        return {
          orderPlaced: true,
          orderId: result.orderId,
          executionPrice: result.price,
          executionStatus: result.status as any,
        };
      } catch (error) {
        this.logger.error({ error }, 'Trade execution failed');
        return {
          orderPlaced: false,
          executionStatus: 'rejected',
          error: (error as Error).message,
        };
      }
    };

    // Node: Generate summary
    const summaryNode = async (state: TradingRequestStateType): Promise<Partial<TradingRequestStateType>> => {
      this.logger.info('Trading request: Generating summary');

      const summary = state.orderPlaced
        ? `Trade executed successfully:
- Order ID: ${state.orderId}
- ${state.side.toUpperCase()} ${state.amount} ${state.ticker}
- Execution Price: $${state.executionPrice}
- Status: ${state.executionStatus}`
        : `Trade not executed:
- Reason: ${state.userApproved ? 'Execution failed' : 'User rejected'}`;

      return {
        summary,
        output: summary,
      };
    };

    // Add nodes
    graph
      .addNode('analyze', analyzeNode)
      .addNode('calculate_risk', calculateRiskNode)
      .addNode('request_approval', requestApprovalNode)
      .addNode('execute_trade', executeTradeNode)
      .addNode('summary', summaryNode);

    // Define edges
    (graph as any).addEdge('__start__', 'analyze');
    (graph as any).addEdge('analyze', 'calculate_risk');
    (graph as any).addEdge('calculate_risk', 'request_approval');

    // Conditional: After approval, execute or reject
    (graph as any).addConditionalEdges('request_approval', (state: any) => {
      // In production, this would check if user approved via interrupt resume
      return state.userApproved ? 'execute_trade' : 'summary';
    });

    (graph as any).addEdge('execute_trade', 'summary');
    (graph as any).addEdge('summary', '__end__');

    return graph;
  }
}

/**
 * Factory function to create and compile workflow
 */
export async function createTradingRequestWorkflow(
  model: BaseChatModel,
  marketDataFn: (ticker: string) => Promise<{ price: number; [key: string]: unknown }>,
  executeTradeFn: (order: any) => Promise<{ orderId: string; status: string; price: number }>,
  logger: FastifyBaseLogger,
  configPath: string
): Promise<TradingRequestWorkflow> {
  const { readFile } = await import('fs/promises');
  const yaml = await import('js-yaml');

  // Load config
  const configContent = await readFile(configPath, 'utf-8');
  const config = yaml.load(configContent) as WorkflowConfig;

  // Create workflow
  const workflow = new TradingRequestWorkflow(
    config,
    model,
    marketDataFn,
    executeTradeFn,
    logger
  );

  // Compile graph
  workflow.compile();

  return workflow;
}
