<?php

namespace App\Console\Commands;

use Carbon\Carbon;
use App\Models\UserPlan;
use App\Models\Transaction;
use App\Enum\UserPlanStatus;
use App\Enum\TransactionType;
use App\Enum\TransactionMethod;
use App\Enum\TransactionStatus;
use Illuminate\Console\Command;
use App\Enum\TransactionDirection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class ProcessDailyProfit extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:process-daily-profit';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Process daily profit for active trading plans';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        // Temporary debug — remove after finding the error
        \Log::channel('single')->info('ProcessDailyProfit started at ' . now());

        try {
            $this->processPlans();
        } catch (\Throwable $e) {
            \Log::channel('single')->error('REAL ERROR: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine());
            \Log::channel('single')->error($e->getTraceAsString());
            $this->error($e->getMessage());
            return Command::FAILURE;
        }

        return Command::SUCCESS;
    }

    private function processPlans()
    {
        $today = Carbon::today();

        UserPlan::where('status', UserPlanStatus::ACTIVE)
            ->whereDate('starts_at', '<=', $today)
            ->whereColumn('days_processed', '<', 'duration')
            ->chunkById(100, function ($userPlans) use ($today) {

                foreach ($userPlans as $plan) {

                    try {

                        DB::transaction(function () use ($plan, $today) {

                            $userPlan = UserPlan::where('id', $plan->id)
                                ->lockForUpdate()
                                ->first();

                            if (!$userPlan) {
                                return;
                            }

                            if ($userPlan->days_processed >= $userPlan->duration) {
                                $this->completePlan($userPlan);
                                return;
                            }

                            $alreadyCredited = Transaction::where('other_reference_id', $userPlan->id)
                                ->where('type', TransactionType::PROFIT)
                                ->whereDate('transaction_at', $today)
                                ->exists();

                            if ($alreadyCredited) {
                                return;
                            }

                            $profit = $this->calculateProfit($userPlan);

                            if ($profit <= 0) {
                                Log::warning("Plan {$userPlan->id} calculated zero or negative profit. Skipping.");
                                return;
                            }

                            $user = $userPlan->user()->lockForUpdate()->first();

                            if (!$user) {
                                Log::error("Plan {$userPlan->id} has no associated user. Skipping.");
                                return;
                            }

                            $user->profit_balance += $profit;
                            $user->save();

                            $userPlan->increment('days_processed');

                            $planName = $userPlan->plan->name ?? 'Unknown Plan';

                            Transaction::create([
                                'user_id'            => $user->id,
                                'type'               => TransactionType::PROFIT,
                                'direction'          => TransactionDirection::CREDIT,
                                'description'        => 'Daily profit from ' . $planName,
                                'amount'             => $profit,
                                'method'             => TransactionMethod::TRADE,
                                'transaction_at'     => now(),
                                'reference_id'       => generateReferenceId(),
                                'other_reference_id' => $userPlan->id,
                                'status'             => TransactionStatus::COMPLETED,
                            ]);

                            if ($userPlan->days_processed >= $userPlan->duration) {
                                $this->completePlan($userPlan);
                            }
                        });
                    } catch (\Throwable $e) {
                        Log::error("ProcessDailyProfit failed for plan {$plan->id}: " . $e->getMessage(), [
                            'plan_id' => $plan->id,
                            'trace'   => $e->getTraceAsString(),
                        ]);
                        continue;
                    }
                }
            });

        return Command::SUCCESS;
    }

    protected function calculateProfit(UserPlan $userPlan)
    {
        $initialCapital = $userPlan->amount;
        $capital        = $initialCapital;

        $dailyRate  = $userPlan->daily_profit / 100;
        $multiplier = (int) ($userPlan->plan->daily_profit_multiplication ?? 0);
        $trades     = (int) ($userPlan->trades_per_day ?? 0);

        // No trades_per_day configured — fall back to simple/multiplied daily rate
        if ($trades <= 0) {

            if ($multiplier <= 0) {
                return round($capital * $dailyRate, 2);
            }

            for ($i = 0; $i < $multiplier; $i++) {
                $capital += $capital * $dailyRate;
            }

            return round($capital - $initialCapital, 2);
        }

        // trades_per_day is set — compound across trades
        $ratePerTrade = $dailyRate / $trades;

        for ($t = 0; $t < $trades; $t++) {

            if ($multiplier <= 0) {
                $capital += $capital * $ratePerTrade;
            } else {
                for ($m = 0; $m < $multiplier; $m++) {
                    $capital += $capital * $ratePerTrade;
                }
            }
        }

        return round($capital - $initialCapital, 2);
    }

    protected function completePlan(UserPlan $userPlan)
    {
        DB::transaction(function () use ($userPlan) {

            $user = $userPlan->user()->lockForUpdate()->first();

            if (!$user) {
                Log::error("completePlan: No user found for plan {$userPlan->id}. Capital not returned.");
                return;
            }

            $user->balance += $userPlan->amount;
            $user->save();

            $userPlan->update([
                'status' => UserPlanStatus::COMPLETED,
            ]);

            $planName = $userPlan->plan->name ?? 'Unknown Plan';

            Transaction::create([
                'user_id'            => $user->id,
                'type'               => TransactionType::CAPITAL_RETURN,
                'direction'          => TransactionDirection::CREDIT,
                'description'        => 'Capital returned from completed ' . $planName,
                'amount'             => $userPlan->amount,
                'method'             => TransactionMethod::TRADE,
                'transaction_at'     => now(),
                'reference_id'       => generateReferenceId(),
                'other_reference_id' => $userPlan->id,
                'status'             => TransactionStatus::COMPLETED,
            ]);
        });

        $this->info("Plan {$userPlan->id} completed.");
    }
}
