<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use App\Models\{User, Plan, UserPlan, UserPlanItem, UserPlanRecord, UserPlanRecordItem, UserSystemRole};
use App\Services\UserService;
use Exception;
use Carbon\Carbon;

class SSOController extends Controller
{
    private UserService $UserService;

    public function __construct(UserService $UserService)
    {
        $this->UserService = $UserService;
    }

    public function handleCallback(Request $request)
    {
        $code = $request->query('code');

        $authHeader = base64_encode(config('sso.client_id') . ':' . config('sso.client_secret'));

        $response = Http::asForm()->withHeaders([
            'Authorization' => 'Basic ' . $authHeader,
        ])->post(config('sso.token_uri'), [
            'grant_type' => 'authorization_code',
            'code' => $code,
            'redirect_uri' => config('sso.redirect_uri'),
        ]);

        if (!$response->successful()) {
            Log::error('SSO token exchange failed', ['code' => $code, 'response' => $response->body()]);
            return redirect("/sso-login?error=token_exchange_failed");
        }

        $tokens = $response->json();
        $id_token = $tokens['id_token'];
        $parts = explode('.', $id_token);
        $payload = json_decode(base64_decode(strtr($parts[1], '-_', '+/')), true);

        Log::info('SSO Payload', $payload);

        DB::beginTransaction();
        try {
            $user = User::where('email', $payload['email'])->first();
            $authorities = explode(',', $payload['authorities'] ?? '');
            $subsystemMap = [
                'SM-SI' => 1,
                'SM-EFW' => 2,
                'SM-CSM' => 3,
            ];

            if (!$user) {
                $user = User::create([
                    'email' => $payload['email'],
                    'name' => $payload['name'] ?? null,
                    'permission' => '100',
                    'password' => Hash::make(Str::random(8)),
                    'api_token' => Str::random(64),
                    'uuid' => Str::random(64),
                    'email_verified_at' => now(),
                ]);
                $this->createUserPlansIfNeeded($user, $authorities, $subsystemMap);
            } else {
                $user->update(['name' => $payload['name'] ?? $user->name]);

                if ($user->permission === '100') {
                    $this->createUserPlansIfNeeded($user, $authorities, $subsystemMap);
                }
            }

            if ($user->permission === '100') {
                $this->updateUserSystemRoles($user, $authorities, $subsystemMap);

                foreach ($user->subUser as $subUser) {
                    $this->updateUserSystemRoles($subUser, [], $subsystemMap, 'parent', $user);
                }
            }

            DB::commit();
        } catch (\Throwable $e) {
            DB::rollback();
            Log::error("SSO handleCallback failed: " . $e->getMessage());
            return response()->json(['status' => false, 'message' => $e->getMessage()], 500);
        }

        Auth::login($user);

        return redirect(config('app.url') . "/sso-login?sso_token={$tokens['access_token']}&api_token={$user->api_token}");
    }

    private function createUserPlansIfNeeded(User $user, array $authorities, array $subsystemMap)
    {
        foreach ($subsystemMap as $key => $subSystemId) {
            if (!in_array($key, $authorities)) continue;

            $exists = UserPlan::where('user_id', $user->id)->where('sub_system_id', $subSystemId)->exists();
            if ($exists) continue;

            $plan = Plan::with('items')->where('sub_system_id', $subSystemId)->orderBy('id')->first();
            if (!$plan) continue;

            $count = UserPlan::where('sub_system_id', $subSystemId)->whereDate('created_at', now()->toDateString())->count() + 1;
            $orderNumber = $key . now()->format('ymd') . str_pad($count, 2, '0', STR_PAD_LEFT);

            $userPlan = UserPlan::create([
                'user_id' => $user->id,
                'sub_system_id' => $subSystemId,
                'plan_name' => $plan->name,
                'years' => $plan->years,
                'price' => $plan->price,
                'state' => 1,
                'open_date' => now()->toDateString(),
                'expiry_date' => now()->addYears($plan->years)->toDateString(),
                'order_number' => $orderNumber,
            ]);

            foreach ($plan->items as $item) {
                UserPlanItem::create([
                    'user_plan_id' => $userPlan->id,
                    'item_id' => $item->item_id,
                    'amount' => $item->amount,
                ]);
            }

            $record = UserPlanRecord::create([
                'user_plan_id' => $userPlan->id,
                'sub_system_id' => $subSystemId,
                'plan_name' => $plan->name,
                'years' => $plan->years,
                'price' => $plan->price,
                'type' => 0,
                'open_date' => now()->toDateString(),
                'expiry_date' => now()->addYears($plan->years)->toDateString(),
                'creator' => $user->id,
            ]);

            foreach ($plan->items as $item) {
                UserPlanRecordItem::create([
                    'user_plan_record_id' => $record->id,
                    'item_id' => $item->item_id,
                    'amount' => $item->amount,
                ]);
            }

            UserSystemRole::updateOrCreate([
                'user_id' => $user->id,
                'sub_system_id' => $subSystemId,
            ], [
                'role' => 'main',
                'state' => true,
            ]);
        }
    }

    private function updateUserSystemRoles(User $user, array $authorities, array $subsystemMap, string $source = 'self', ?User $parent = null)
    {
        foreach ($subsystemMap as $key => $subSystemId) {
            if ($source === 'self') {
                $shouldEnable = in_array($key, $authorities);
                $record = UserSystemRole::firstOrNew(['user_id' => $user->id, 'sub_system_id' => $subSystemId]);

                if ($record->exists && $record->role === 'none') {
                    $record->state = false;
                } else {
                    $record->role = $record->role ?: ($user->permission === '100' ? 'main' : 'none');
                    $record->state = $record->role === 'none' ? false : $shouldEnable;
                }

                $record->save();
            }

            if ($source === 'parent' && $parent) {
                $parentRole = UserSystemRole::where('user_id', $parent->id)->where('sub_system_id', $subSystemId)->first();
                $parentState = $parentRole && $parentRole->state;

                $record = UserSystemRole::firstOrNew(['user_id' => $user->id, 'sub_system_id' => $subSystemId]);
                $record->role = $record->role ?: 'none';
                $record->state = $record->role === 'none' ? false : $parentState;
                $record->save();
            }
        }
    }

    public function verifyToken(Request $request)
    {
        $token = $request->input('token');
        if (!$token) {
            return response()->json(['active' => false, 'error' => 'Token is required'], 400);
        }

        $response = Http::asForm()->withHeaders([
            'Authorization' => 'Basic ' . base64_encode(config('sso.client_id') . ':' . config('sso.client_secret')),
        ])->post(config('sso.introspection_uri'), [
            'token' => $token,
            'token_type_hint' => 'access_token',
        ]);

        return response()->json($response->json());
    }
}
