<?php

namespace App\Http\Controllers;

use App\Models\Trading;
use App\Models\Investment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\Funding;
use App\Models\TradingPlan;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Log;

class TradingController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    public function getCoinBalance($coin) {
        $bal = 0;
        $balance = Funding::where('gateway', $coin)->where('user_id', (int)Auth::id())->where('status', 'successful')->sum("amount");
        $bal += $balance;
        $trading = Trading::where('pair', $coin)->where('user_id', (int)Auth::id())->sum("profit");
        $bal += $trading;

        $investments = Investment::where('payment_source', $coin)->where('user_id', (int)Auth::id())->sum("amount_invested");
        $bal -= $investments;

        $investments = Investment::where('payment_source', $coin)->where('user_id', (int)Auth::id())->sum("earning");
        $bal += $investments;

        return $bal;
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $request->validate([
            'amount' => 'required|numeric|min:0',
            'stop_loss' => 'nullable|numeric|min:0',
            'take_profit' => 'nullable|numeric|min:0',
            'timer_units' => 'required|integer',
            'trading_pair' => 'required|string',
            'order_type' => 'required|string',
            'pair' => 'required|string',
            'entry_point' => 'required|numeric|min:0',
            
            // Advanced order fields
            'trading_type' => 'nullable|string|in:Spot,Futures',
            'limit_price' => 'nullable|numeric|min:0',
            'trigger_price' => 'nullable|numeric|min:0',
            'order_quantity' => 'nullable|numeric|min:0',
            'post_only' => 'nullable|boolean',
            'reduce_only' => 'nullable|boolean',
            'time_in_force' => 'nullable|string|in:GTC,IOC,FOK',
            
            // Futures specific
            'leverage' => 'nullable|numeric|min:1|max:125',
            'margin_type' => 'nullable|string|in:Cross,Isolated',
            
            // TWAP specific
            'twap_duration' => 'nullable|integer|min:1',
            'twap_frequency' => 'nullable|string|in:30S,1M,3M,5M,10M,15M,30M',
            'twap_quantity_per_order' => 'nullable|numeric|min:0',
            'twap_randomize' => 'nullable|boolean',
            
            // Iceberg specific
            'iceberg_visible_quantity' => 'nullable|numeric|min:0',
            'iceberg_chase_option' => 'nullable|string',
            
            // Scaled Order specific
            'scaled_min_price' => 'nullable|numeric|min:0',
            'scaled_max_price' => 'nullable|numeric|min:0',
            'scaled_orders_count' => 'nullable|integer|min:1|max:100',
            'scaled_orders_data' => 'nullable|string',
            
            // Trailing Stop specific
            'trailing_type' => 'nullable|string|in:Percentage,Amount',
            'trailing_value' => 'nullable|numeric|min:0',
            'activation_price' => 'nullable|numeric|min:0',
            
            // Chase Limit Order specific
            'chase_price_type' => 'nullable|string|in:Bid1,Ask1,Bid2,Ask2,Bid3,Ask3,Last Price',
            'max_chase_distance' => 'nullable|numeric|min:0',
            'chase_interval' => 'nullable|string|in:1S,2S,5S,10S,30S',
            
            // OCO specific
            'oco_stop_price' => 'nullable|numeric|min:0',
            'oco_limit_price' => 'nullable|numeric|min:0',
            
            // Conditional specific
            'condition_type' => 'nullable|string|in:LastPrice,MarkPrice,IndexPrice',
            'condition_operator' => 'nullable|string|in:>=,<=',
            'condition_value' => 'nullable|numeric|min:0',
        ]);

        // Get the trading plan from timer_units (which contains the plan ID)
        $planId = $request->timer_units;
        $plan = TradingPlan::find($planId);
        if (!$plan) {
            return response()->json([
                'status' => 'error',
                'message' => 'invalid request, please select a valid trading plan'
            ], 400);
        }

        // Check user balance
        if (Auth::user()->balance() < $request->amount) {
            return response()->json([
                'status' => 'error',
                'message' => 'insufficient funds, kindly fund your account to trade'
            ], 400);
        }

        if ($request->amount < $plan->min_amount || $request->amount > $plan->max_amount) {
            return response()->json([
                'status' => 'error',
                'message' => 'amount must not be less than $'.$plan->min_amount. ' or greater than $'.$plan->max_amount
            ], 400);
        }

        // Get the duration string from the trading plan
        $duration_string = $plan->duration;
        
        // Create trading record with all advanced fields
        $trading = new Trading;
        $trading->user_id = Auth::id();
        $trading->amount = $request->amount;
        $trading->duration = $duration_string;
        $trading->profit = 0;
        $trading->status = 'open';
        $trading->order_type = $request->order_type;
        $trading->pair = $request->pair;
        $trading->stop_loss = $request->stop_loss;
        $trading->take_profit = $request->take_profit;
        // Set temporary end_time (will be recalculated after save from created_at + duration)
        $trading->end_time = strtotime('+'.$duration_string);
        $trading->trading_plan_id = $plan->id;
        $trading->percentage = 0;
        $trading->entry_point = $request->entry_point;
        
        // Advanced order fields
        $trading->trading_type = $request->trading_type ?? 'Spot';
        $trading->limit_price = $request->limit_price;
        $trading->trigger_price = $request->trigger_price;
        $trading->order_quantity = $request->order_quantity ?? $request->amount;
        $trading->post_only = $request->post_only ?? false;
        $trading->reduce_only = $request->reduce_only ?? false;
        $trading->time_in_force = $request->time_in_force ?? 'GTC';
        
        // Futures specific
        if ($request->trading_type === 'Futures') {
            $trading->leverage = $request->leverage ?? 10;
            $trading->margin_type = $request->margin_type ?? 'Cross';
        }
        
        // TWAP specific
        if ($request->order_type === 'TWAP') {
            $trading->twap_duration = $request->twap_duration;
            $trading->twap_frequency = $request->twap_frequency;
            $trading->twap_quantity_per_order = $request->twap_quantity_per_order;
            $trading->twap_randomize = $request->twap_randomize ?? false;
        }
        
        // Iceberg specific
        if ($request->order_type === 'Iceberg') {
            $trading->iceberg_visible_quantity = $request->iceberg_visible_quantity;
            $trading->iceberg_chase_option = $request->iceberg_chase_option;
        }
        
        // Scaled Order specific
        if ($request->order_type === 'Scaled Order') {
            $trading->scaled_min_price = $request->scaled_min_price;
            $trading->scaled_max_price = $request->scaled_max_price;
            $trading->scaled_orders_count = $request->scaled_orders_count;
            $trading->scaled_orders_data = $request->scaled_orders_data;
        }
        
        // Trailing Stop specific
        if ($request->order_type === 'Trailing Stop') {
            $trading->trailing_type = $request->trailing_type;
            $trading->trailing_value = $request->trailing_value;
            $trading->activation_price = $request->activation_price;
        }
        
        // Chase Limit Order specific
        if ($request->order_type === 'Chase Limit Order') {
            $trading->chase_price_type = $request->chase_price_type;
            $trading->max_chase_distance = $request->max_chase_distance;
            $trading->chase_interval = $request->chase_interval;
        }
        
        // OCO specific
        if ($request->order_type === 'OCO') {
            $trading->oco_stop_price = $request->oco_stop_price;
            $trading->oco_limit_price = $request->oco_limit_price;
        }
        
        // Conditional specific
        if ($request->order_type === 'Conditional') {
            $trading->condition_type = $request->condition_type;
            $trading->condition_operator = $request->condition_operator;
            $trading->condition_value = $request->condition_value;
        }

        // Initialize order history
        $trading->order_history = json_encode([
            [
                'action' => 'created',
                'timestamp' => now(),
                'user_id' => Auth::id(),
                'data' => $request->all()
            ]
        ]);

        // Save first to get created_at timestamp
        $trading->save();
        
        // Now calculate end_time based on created_at + duration using strtotime
        // This ensures end_time is always calculated from the actual creation time
        $createdAtTimestamp = strtotime($trading->created_at);
        $trading->end_time = strtotime('+'.$duration_string, $createdAtTimestamp);
        $trading->save();
        
        // Log for debugging
        Log::info('Trade created with end_time calculated from created_at', [
            'trading_id' => $trading->id,
            'created_at' => $trading->created_at,
            'created_at_timestamp' => $createdAtTimestamp,
            'duration_string' => $duration_string,
            'end_time' => $trading->end_time,
            'end_time_formatted' => date('Y-m-d H:i:s', $trading->end_time),
            'duration_seconds' => $trading->end_time - $createdAtTimestamp
        ]);

        $tradings = Trading::orderByDesc('id')->where('user_id', (int)Auth::id())->take(10)->get()->load(['plan']);
       
        return response()->json([
            'status' => 'success',
            'message' => 'trade initiated successfully',
            'tradings' => $tradings
        ], 200);
    }

    /**
     * Validate advanced order type specific requirements
     */
    private function validateAdvancedOrderType($request, $validator)
    {
        $orderType = $request->order_type;
        
        // Add specific validation rules based on order type
        switch ($orderType) {
            case 'TWAP':
                if (!$request->twap_duration || !$request->twap_frequency) {
                    $validator->errors()->add('twap_validation', 'TWAP orders require duration and frequency');
                }
                break;
                
            case 'Iceberg':
                if (!$request->iceberg_visible_quantity) {
                    $validator->errors()->add('iceberg_validation', 'Iceberg orders require visible quantity');
                }
                break;
                
            case 'Scaled Order':
                if (!$request->scaled_min_price || !$request->scaled_max_price || !$request->scaled_orders_count) {
                    $validator->errors()->add('scaled_validation', 'Scaled orders require min price, max price, and order count');
                }
                if ($request->scaled_min_price >= $request->scaled_max_price) {
                    $validator->errors()->add('scaled_validation', 'Min price must be less than max price');
                }
                break;
                
            case 'Trailing Stop':
                if (!$request->trailing_type || !$request->trailing_value) {
                    $validator->errors()->add('trailing_validation', 'Trailing Stop orders require type and value');
                }
                break;
                
            case 'Chase Limit Order':
                if (!$request->chase_price_type || !$request->chase_interval) {
                    $validator->errors()->add('chase_validation', 'Chase Limit orders require price type and interval');
                }
                break;
                
            case 'OCO':
                if (!$request->oco_stop_price || !$request->oco_limit_price) {
                    $validator->errors()->add('oco_validation', 'OCO orders require both stop price and limit price');
                }
                break;
                
            case 'Conditional':
                if (!$request->condition_type || !$request->condition_operator || !$request->condition_value) {
                    $validator->errors()->add('conditional_validation', 'Conditional orders require type, operator, and value');
                }
                break;
        }
        
        return $validator;
    }

    /**
     * Display the specified resource.
     *
     * @param  \App\Models\Trading  $trading
     * @return \Illuminate\Http\Response
     */
    public function show(Trading $trading)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  \App\Models\Trading  $trading
     * @return \Illuminate\Http\Response
     */
    public function edit(Trading $trading)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Models\Trading  $trading
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, Trading $trading)
    {
        $request->validate([
            'trading_id' => 'required|integer',
            'profit' => 'required|numeric',   
            'percentage' => 'required|numeric'         
        ]);

        $trade = $trading->find($request->trading_id);
        if (!$trade) {
            return response()->json([
                'status' => 'error',
                'message' => 'Trade not found'
            ], 400);
        }

        // Update order history
        $orderHistory = json_decode($trade->order_history, true) ?? [];
        $orderHistory[] = [
            'action' => 'closed',
            'timestamp' => now(),
            'user_id' => Auth::id(),
            'profit' => $request->profit,
            'percentage' => $request->percentage
        ];

        $trade->profit = $request->profit;
        $trade->status = 'closed';
        $trade->end_time = strtotime('now');
        $trade->percentage = $request->percentage;
        $trade->filled_at = now();
        $trade->filled_quantity = $trade->order_quantity;
        $trade->avg_fill_price = $trade->limit_price ?? $trade->entry_point;
        $trade->order_history = json_encode($orderHistory);
        $trade->save();

        // Log the trading closure
        Log::info('Trading order closed', [
            'user_id' => Auth::id(),
            'trading_id' => $trade->id,
            'profit' => $request->profit,
            'percentage' => $request->percentage
        ]);

        $tradings = Trading::orderByDesc('id')
            ->where('user_id', (int)Auth::id())
            ->take(10)
            ->get()
            ->load(['plan']);
            
        return response()->json([
            'status' => 'success',
            'message' => 'Trading #'.$trade->id.' closed successfully!',
            'tradings' => $tradings
        ], 200);
    }

    /**
     * Admin function to modify trade results
     */
    public function adminModifyTrade(Request $request)
    {
        $request->validate([
            'trading_id' => 'required|integer',
            'profit' => 'nullable|numeric',
            'percentage' => 'nullable|numeric',
            'status' => 'nullable|string|in:open,closed,cancelled',
            'admin_notes' => 'nullable|string'
        ]);

        $trade = Trading::find($request->trading_id);
        if (!$trade) {
            return response()->json([
                'status' => 'error',
                'message' => 'Trade not found'
            ], 400);
        }

        // Update order history for admin modification
        $orderHistory = json_decode($trade->order_history, true) ?? [];
        $orderHistory[] = [
            'action' => 'admin_modified',
            'timestamp' => now(),
            'admin_id' => Auth::id(),
            'old_values' => [
                'profit' => $trade->profit,
                'percentage' => $trade->percentage,
                'status' => $trade->status
            ],
            'new_values' => [
                'profit' => $request->profit,
                'percentage' => $request->percentage,
                'status' => $request->status
            ],
            'admin_notes' => $request->admin_notes
        ];

        // Update trade fields
        if ($request->has('profit')) $trade->profit = $request->profit;
        if ($request->has('percentage')) $trade->percentage = $request->percentage;
        if ($request->has('status')) $trade->status = $request->status;
        if ($request->has('admin_notes')) $trade->admin_notes = $request->admin_notes;
        
        $trade->admin_modified = true;
        $trade->admin_modified_at = now();
        $trade->order_history = json_encode($orderHistory);
        $trade->save();

        // Log the admin modification
        Log::info('Trading order modified by admin', [
            'admin_id' => Auth::id(),
            'trading_id' => $trade->id,
            'modifications' => $request->all()
        ]);

        return response()->json([
            'status' => 'success',
            'message' => 'Trade modified successfully',
            'trade' => $trade
        ], 200);
    }

    /**
     * Get user's trading history with enhanced details
     */
    public function getUserTradingHistory(Request $request)
    {
        $perPage = $request->input('per_page', 10);
        $status = $request->input('status', 'all');
        $orderType = $request->input('order_type', 'all');
        $tradingType = $request->input('trading_type', 'all');

        $query = Trading::where('user_id', Auth::id())
            ->orderByDesc('created_at');

        if ($status !== 'all') {
            $query->where('status', $status);
        }

        if ($orderType !== 'all') {
            $query->where('order_type', $orderType);
        }

        if ($tradingType !== 'all') {
            $query->where('trading_type', $tradingType);
        }

        $tradings = $query->with(['plan'])->paginate($perPage);

        return response()->json([
            'status' => 'success',
            'tradings' => $tradings
        ], 200);
    }

    /**
     * Get all trading orders for admin management
     */
    public function getAdminTradingOrders(Request $request)
    {
        $perPage = $request->input('per_page', 20);
        $status = $request->input('status', 'all');
        $orderType = $request->input('order_type', 'all');
        $tradingType = $request->input('trading_type', 'all');
        $userId = $request->input('user_id', 'all');

        $query = Trading::with(['plan', 'user'])
            ->orderByDesc('created_at');

        if ($status !== 'all') {
            $query->where('status', $status);
        }

        if ($orderType !== 'all') {
            $query->where('order_type', $orderType);
        }

        if ($tradingType !== 'all') {
            $query->where('trading_type', $tradingType);
        }

        if ($userId !== 'all') {
            $query->where('user_id', $userId);
        }

        $tradings = $query->paginate($perPage);

        return response()->json([
            'status' => 'success',
            'tradings' => $tradings
        ], 200);
    }

    /**
     * Get detailed trading order for admin
     */
    public function getAdminTradingOrder($id)
    {
        $trading = Trading::with(['plan', 'user'])->find($id);

        if (!$trading) {
            return response()->json([
                'status' => 'error',
                'message' => 'Trading order not found'
            ], 404);
        }

        return response()->json([
            'status' => 'success',
            'trading' => $trading
        ], 200);
    }

    /**
     * Cron job endpoint to automatically close expired trades
     * This should be called periodically (e.g., every minute) via a cron job
     * 
     * @return \Illuminate\Http\Response
     */
    public function cronCloseExpiredTrades()
    {
        try {
            $completedTrades = 0;
            $failedTrades = 0;
            $currentTime = time();
            
            // Get all open trades that are due
            $dueTrades = Trading::where('status', 'open')
                ->where('end_time', '<=', $currentTime)
                ->with(['plan', 'user'])
                ->get();
            
            Log::info("Cron job: Found " . $dueTrades->count() . " trades due for completion");
            
            foreach ($dueTrades as $trade) {
                try {
                    // Calculate profit/loss based on trading plan
                    $profit = $this->calculateTradeResult($trade);
                    
                    // Update trade
                    $trade->profit = $profit;
                    $trade->status = 'closed';
                    $trade->end_time = $currentTime;
                    $trade->percentage = ($profit / $trade->amount) * 100;
                    $trade->save();
                    
                    // Update user balance
                    $this->updateUserBalance($trade);
                    
                    // Send notification to user
                    $this->notifyUserOfTradeCompletion($trade);
                    
                    // Notify admin
                    $this->notifyAdminOfTradeCompletion($trade);
                    
                    $completedTrades++;
                    
                    Log::info("Cron job: Successfully completed trade ID: " . $trade->id . " for user: " . $trade->user->name);
                    
                } catch (\Exception $e) {
                    $failedTrades++;
                    Log::error("Cron job: Failed to complete trade ID: " . $trade->id . " - Error: " . $e->getMessage());
                }
            }
            
            return response()->json([
                'status' => 'success',
                'message' => "Cron job completed successfully. Completed: {$completedTrades}, Failed: {$failedTrades}",
                'completed_trades' => $completedTrades,
                'failed_trades' => $failedTrades,
                'total_due_trades' => $dueTrades->count()
            ], 200);
            
        } catch (\Exception $e) {
            Log::error("Cron job: General error - " . $e->getMessage());
            
            return response()->json([
                'status' => 'error',
                'message' => 'Cron job failed: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Calculate trade percentage using the same algorithm as frontend
     * 
     * @param float $minRange
     * @param float $maxRange
     * @param string $finalResult (profit, loss, profit_loss)
     * @return float
     */
    private function calculateTradePercentage($minRange, $maxRange, $finalResult)
    {
        switch ($finalResult) {
            case 'profit':
                $minPercent = $minRange / 100;
                $maxPercent = $maxRange / 100;
                return mt_rand($minPercent * 10000, $maxPercent * 10000) / 10000;
                break;

            case 'loss':
                $minLoss = -$minRange / 100;
                $maxLoss = -$maxRange / 100;
                return mt_rand($minLoss * 10000, $maxLoss * 10000) / 10000;
                break;

            case 'profit_loss':
                $minProfitLoss = -$minRange / 100;
                $maxProfitLoss = $maxRange / 100;
                return mt_rand($minProfitLoss * 10000, $maxProfitLoss * 10000) / 10000;
                break;

            default:
                return mt_rand($minRange * 100, $maxRange * 100) / 10000;
                break;
        }
    }

    /**
     * Helper method to close a trade
     * 
     * @param Trading $trade
     * @param float $percentage
     * @param float $profit
     * @param string $reason
     * @return void
     */
    private function closeTrade($trade, $percentage, $profit, $reason = 'time_expired')
    {
        $currentTime = time();

        // Update order history
        $orderHistory = json_decode($trade->order_history, true) ?? [];
        $orderHistory[] = [
            'action' => 'closed_by_cron',
            'reason' => $reason,
            'timestamp' => now(),
            'profit' => $profit,
            'percentage' => $percentage
        ];

        // Update trade
        $trade->profit = $profit;
        $trade->status = 'closed';
        $trade->end_time = $currentTime;
        $trade->percentage = $percentage;
        $trade->filled_at = now();
        $trade->filled_quantity = $trade->order_quantity ?? $trade->amount;
        $trade->avg_fill_price = $trade->limit_price ?? $trade->entry_point;
        $trade->order_history = json_encode($orderHistory);
        $trade->save();

        Log::info('Trade closed by cron job', [
            'trading_id' => $trade->id,
            'user_id' => $trade->user_id,
            'reason' => $reason,
            'profit' => $profit,
            'percentage' => $percentage
        ]);
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  \App\Models\Trading  $trading
     * @return \Illuminate\Http\Response
     */
    public function destroy(Trading $trading)
    {
        //
    }
}
