<?php

namespace Tests\Feature;

use Tests\TestCase;
use App\Models\User;
use App\Models\Plan;
use App\Models\MiningSession;
use App\Services\MiningService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Laravel\Passport\Passport;

class MiningApiTest extends TestCase
{
    use RefreshDatabase, WithFaker;

    protected $user;
    protected $plan;
    protected $miningService;

    public function setUp(): void
    {
        parent::setUp();
        
        $this->miningService = app(MiningService::class);
        
        // Create test user
        $this->user = User::factory()->create([
            'balance' => 100.00,
            'coin_balance' => 0.00,
            'staked' => 0.00,
            'plan_id' => null
        ]);

        // Create test plan
        $this->plan = Plan::factory()->create([
            'title' => 'Test Plan',
            'price' => 50.00,
            'miners' => 2,
            'speed' => 150,
            'period' => 24,
            'min_return_per_day' => 0.535,
            'max_return_per_day' => 1.535,
            'maintenance_cost' => 0.1,
            'status' => 'active'
        ]);

        Passport::actingAs($this->user);
    }

    /** @test */
    public function user_can_get_all_mining_plans()
    {
        $response = $this->getJson('/api/user/mining-plans');

        $response->assertStatus(200)
                ->assertJsonStructure([
                    'status',
                    'message',
                    'data' => [
                        'plans' => [
                            '*' => [
                                'id',
                                'title',
                                'price',
                                'miners',
                                'speed',
                                'period',
                                'daily_earnings',
                                'hourly_earnings',
                                'roi_percentage',
                                'is_user_plan',
                                'can_purchase'
                            ]
                        ],
                        'user_plan',
                        'user_balance',
                        'total_plans'
                    ]
                ]);

        $this->assertEquals('success', $response->json('status'));
    }

    /** @test */
    public function user_can_get_specific_plan_details()
    {
        $response = $this->getJson("/api/user/mining-plans/{$this->plan->id}");

        $response->assertStatus(200)
                ->assertJsonStructure([
                    'status',
                    'message',
                    'data' => [
                        'id',
                        'title',
                        'price',
                        'miners',
                        'speed',
                        'daily_earnings',
                        'statistics' => [
                            'total_subscribers',
                            'active_sessions',
                            'total_earnings_distributed'
                        ]
                    ]
                ]);

        $this->assertEquals($this->plan->title, $response->json('data.title'));
    }

    /** @test */
    public function user_can_purchase_mining_plan_with_sufficient_balance()
    {
        $response = $this->postJson("/api/user/mining-plans/{$this->plan->id}/purchase");

        $response->assertStatus(200)
                ->assertJsonStructure([
                    'status',
                    'message',
                    'data' => [
                        'plan',
                        'user' => [
                            'balance',
                            'staked',
                            'plan_id'
                        ],
                        'transaction_recorded',
                        'can_start_mining'
                    ]
                ]);

        $this->assertEquals('success', $response->json('status'));
        
        // Verify user's plan was updated
        $this->user->refresh();
        $this->assertEquals($this->plan->id, $this->user->plan_id);
        $this->assertEquals(50.00, $this->user->balance); // 100 - 50
        $this->assertEquals(50.00, $this->user->staked);
    }

    /** @test */
    public function user_cannot_purchase_plan_with_insufficient_balance()
    {
        $this->user->update(['balance' => 25.00]);

        $response = $this->postJson("/api/user/mining-plans/{$this->plan->id}/purchase");

        $response->assertStatus(400)
                ->assertJson([
                    'status' => 'error',
                    'message' => 'Insufficient balance. Please deposit funds first.'
                ]);
    }

    /** @test */
    public function user_can_get_plan_status()
    {
        // Purchase a plan first
        $this->user->update(['plan_id' => $this->plan->id]);

        $response = $this->getJson('/api/user/mining-plans/user-status');

        $response->assertStatus(200)
                ->assertJsonStructure([
                    'status',
                    'message',
                    'data' => [
                        'has_plan',
                        'plan',
                        'active_session',
                        'can_mine',
                        'user_balance'
                    ]
                ]);

        $this->assertTrue($response->json('data.has_plan'));
        $this->assertTrue($response->json('data.can_mine'));
    }

    /** @test */
    public function user_can_start_mining_session()
    {
        // Purchase a plan first
        $this->user->update(['plan_id' => $this->plan->id]);

        $response = $this->postJson('/api/user/mining/start');

        $response->assertStatus(200)
                ->assertJsonStructure([
                    'status',
                    'message',
                    'data' => [
                        'session' => [
                            'id',
                            'started_at',
                            'expires_at',
                            'total_mined',
                            'remaining_seconds',
                            'is_active',
                            'plan_name'
                        ],
                        'user_balance',
                        'mining_rate_per_minute'
                    ]
                ]);

        $this->assertEquals('success', $response->json('status'));
        
        // Verify session was created
        $this->assertDatabaseHas('mining_sessions', [
            'user_id' => $this->user->id,
            'plan_id' => $this->plan->id,
            'is_active' => true
        ]);
    }

    /** @test */
    public function user_can_get_session_status()
    {
        // Create an active session
        $session = $this->miningService->startMiningSession($this->user, $this->plan);

        $response = $this->getJson('/api/user/mining/status');

        $response->assertStatus(200)
                ->assertJsonStructure([
                    'status',
                    'message',
                    'data' => [
                        'timestamp',
                        'server_time',
                        'has_active_session',
                        'session' => [
                            'id',
                            'total_mined',
                            'remaining_seconds',
                            'mining_rate_per_minute'
                        ],
                        'user_balance',
                        'total_lifetime_mined'
                    ]
                ]);

        $this->assertTrue($response->json('data.has_active_session'));
        $this->assertEquals($session->id, $response->json('data.session.id'));
    }

    /** @test */
    public function user_can_end_mining_session()
    {
        // Create an active session
        $session = $this->miningService->startMiningSession($this->user, $this->plan);

        $response = $this->postJson('/api/user/mining/end-session');

        $response->assertStatus(200)
                ->assertJsonStructure([
                    'status',
                    'message',
                    'data' => [
                        'session_ended',
                        'final_earnings',
                        'user_balance',
                        'ended_at'
                    ]
                ]);

        $this->assertEquals('success', $response->json('status'));
        
        // Verify session was ended
        $session->refresh();
        $this->assertFalse($session->is_active);
    }

    /** @test */
    public function user_can_get_mining_statistics()
    {
        $response = $this->getJson('/api/user/mining/stats');

        $response->assertStatus(200)
                ->assertJsonStructure([
                    'status',
                    'message',
                    'data' => [
                        'server_stats' => [
                            'total_hashrate',
                            'active_miners',
                            'daily_earnings',
                            'network_difficulty'
                        ],
                        'user_stats' => [
                            'lifetime_mined',
                            'current_balance',
                            'active_session',
                            'total_sessions'
                        ],
                        'mining_progress' => [
                            'btc',
                            'eth',
                            'ltc',
                            'doge'
                        ]
                    ]
                ]);

        $this->assertEquals('success', $response->json('status'));
    }

    /** @test */
    public function user_can_get_pool_information()
    {
        $response = $this->getJson('/api/user/mining/pool-info');

        $response->assertStatus(200)
                ->assertJsonStructure([
                    'status',
                    'message',
                    'data' => [
                        'pool_stats' => [
                            'pool_hashrate',
                            'difficulty',
                            'active_miners',
                            'blocks_found_24h'
                        ],
                        'network_info' => [
                            'network_difficulty',
                            'next_difficulty_adjustment',
                            'average_block_time'
                        ],
                        'connectivity' => [
                            'pool_connection',
                            'latency',
                            'connection_quality'
                        ]
                    ]
                ]);

        $this->assertEquals('success', $response->json('status'));
    }

    /** @test */
    public function user_can_get_mining_history()
    {
        // Create some mining sessions
        $sessions = MiningSession::factory()->count(3)->create([
            'user_id' => $this->user->id,
            'plan_id' => $this->plan->id
        ]);

        $response = $this->getJson('/api/user/mining/history');

        $response->assertStatus(200)
                ->assertJsonStructure([
                    'status',
                    'message',
                    'data' => [
                        'sessions' => [
                            '*' => [
                                'id',
                                'plan_name',
                                'started_at',
                                'total_mined',
                                'is_active',
                                'duration_hours'
                            ]
                        ],
                        'summary' => [
                            'total_sessions',
                            'total_earnings',
                            'average_earnings_per_session'
                        ]
                    ]
                ]);

        $this->assertEquals('success', $response->json('status'));
        $this->assertCount(3, $response->json('data.sessions'));
    }

    /** @test */
    public function user_can_get_plans_comparison()
    {
        $response = $this->getJson('/api/user/mining-plans/compare');

        $response->assertStatus(200)
                ->assertJsonStructure([
                    'status',
                    'message',
                    'data' => [
                        'plans' => [
                            '*' => [
                                'id',
                                'title',
                                'daily_earnings',
                                'monthly_earnings',
                                'roi_percentage',
                                'payback_days',
                                'efficiency_score'
                            ]
                        ],
                        'comparison_metrics' => [
                            'best_roi',
                            'fastest_payback',
                            'highest_daily_earnings',
                            'most_efficient'
                        ]
                    ]
                ]);

        $this->assertEquals('success', $response->json('status'));
    }

    /** @test */
    public function user_can_cancel_current_plan()
    {
        // Set user to have a plan
        $this->user->update(['plan_id' => $this->plan->id]);

        $response = $this->postJson('/api/user/mining-plans/cancel');

        $response->assertStatus(200)
                ->assertJsonStructure([
                    'status',
                    'message',
                    'data' => [
                        'plan_cancelled',
                        'active_sessions_ended',
                        'user_balance'
                    ]
                ]);

        $this->assertEquals('success', $response->json('status'));
        
        // Verify plan was cancelled
        $this->user->refresh();
        $this->assertNull($this->user->plan_id);
    }

    /** @test */
    public function user_can_get_comprehensive_dashboard_data()
    {
        $response = $this->getJson('/api/user/mining-dashboard');

        $response->assertStatus(200)
                ->assertJsonStructure([
                    'status',
                    'message',
                    'data' => [
                        'user_info' => [
                            'id',
                            'has_plan',
                            'plan',
                            'can_mine'
                        ],
                        'active_session',
                        'user_statistics' => [
                            'lifetime_mined',
                            'total_sessions',
                            'current_balance'
                        ],
                        'available_plans',
                        'recent_sessions',
                        'server_statistics',
                        'market_data',
                        'notifications'
                    ]
                ]);

        $this->assertEquals('success', $response->json('status'));
    }

    /** @test */
    public function endpoints_require_authentication()
    {
        // Log out the user
        $this->app['auth']->forgetGuards();

        $endpoints = [
            'GET:/api/user/mining-plans',
            'GET:/api/user/mining/status',
            'POST:/api/user/mining/start',
            'GET:/api/user/mining-dashboard'
        ];

        foreach ($endpoints as $endpoint) {
            [$method, $url] = explode(':', $endpoint);
            
            $response = $this->json($method, $url);
            $response->assertStatus(401);
        }
    }

    /** @test */
    public function plan_not_found_returns_404()
    {
        $response = $this->getJson('/api/user/mining-plans/999');
        $response->assertStatus(404)
                ->assertJson([
                    'status' => 'error',
                    'message' => 'Plan not found'
                ]);
    }

    /** @test */
    public function mining_service_calculates_rewards_correctly()
    {
        $session = $this->miningService->startMiningSession($this->user, $this->plan);
        
        // Simulate time passage
        $session->update(['last_calculated_at' => now()->subMinutes(10)]);
        
        $initialMined = $session->total_mined;
        $this->miningService->calculateMiningRewards($session);
        $session->refresh();
        
        $this->assertGreaterThan($initialMined, $session->total_mined);
    }
}
