<?php

namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\SavingsCustomer;
use App\Services\EasypaisaCryptoService;
use DateTime;
use DateTimeZone;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class SavingsEasypaisaController extends Controller
{
    private string $clientId;
    private string $apiKey;
    private string $baseUrl;
    private string $appId;
    private string $merchantId;
    private string $accessToken;
    private $privateKey;

    public function __construct()
    {
        $this->clientId    = config('easypaisa.client_id');
        $this->apiKey      = config('easypaisa.api_key');
        $this->baseUrl     = config('easypaisa.base_url');
        $this->appId       = config('easypaisa.app_id');
        $this->merchantId  = config('easypaisa.merchant_id');
        $this->accessToken = config('easypaisa.access_token');

        $rawKey           = config('easypaisa.private_key');
        $this->privateKey = $rawKey ? openssl_pkey_get_private($rawKey) : null;

        if (!$this->privateKey) {
            Log::error('SavingsEasypaisaController: Invalid or missing private key.');
        }
    }

    // =========================================================================
    //  PUBLIC ENDPOINT  →  POST /api/savings/easypaisa/register
    // =========================================================================

    public function register(Request $request): JsonResponse
    {
        $request->validate([
            'authCode' => 'required|string',
        ]);

        try {
            // ── 1. Call Easypaisa /inquireUserInfo ────────────────────────────
            $result = $this->fetchUserInfo($request->input('authCode'));

            $responseBody    = $result['body'];
            $responseHeaders = $result['headers'];
            $httpStatus      = $result['status'];
            $usedMock        = $result['mock'] ?? false;

            Log::info('SavingsEasypaisaController@register: raw response', [
                'http_status' => $httpStatus,
                'body'        => $responseBody,
                'mock'        => $usedMock,
            ]);

            // ── 2. Guard: must have userInfo + result blocks ──────────────────
            if (empty($responseBody['userInfo']) || empty($responseBody['result'])) {
                Log::warning('SavingsEasypaisaController@register: Unexpected response structure.', [
                    'body' => $responseBody,
                ]);

                return response()->json([
                    'status'  => 400,
                    'message' => 'Invalid or incomplete response received from Easypaisa.',
                    'data'    => $responseBody,
                ], 400);
            }

            $userInfo = $responseBody['userInfo'];
            $epResult = $responseBody['result'];

            // ── 3. Decrypt CNIC ───────────────────────────────────────────────
            $decryptedCnic = $usedMock
                ? ($userInfo['userCnic'] ?? null)
                : $this->resolveDecryptedCnic($responseHeaders, $userInfo['userCnic'] ?? null);

            // ── 4. Derive fields ──────────────────────────────────────────────
            $fullName = trim($userInfo['userName'] ?? '');
            $gender   = $this->deriveGender($decryptedCnic);
            $msisdn   = $userInfo['userMsisdn'] ?? null;
            $dob      = !empty($userInfo['birthDate']) ? $userInfo['birthDate'] : now()->toDateString();

            // ── 5. Upsert savings_customers ───────────────────────────────────
            $customer = SavingsCustomer::updateOrCreate(
                ['open_id' => $userInfo['openId']],
                [
                    'msisdn'                  => $msisdn,
                    'union_id'                => $userInfo['unionId']  ?? null,
                    'auth_id'                 => $userInfo['authId']   ?? null,
                    'full_name'               => $fullName ?: 'Unknown',
                    'cnic'                    => $decryptedCnic,
                    'dob'                     => $dob,
                    'gender'                  => $gender,
                    'email'                   => $msisdn ? $msisdn . '@easypaisa.com' : null,
                    'address'                 => 'Easypaisa Mini App',
                    'city'                    => 'Islamabad',
                    'province'                => 'Punjab',
                    'country'                 => 'Pakistan',
                    'is_active'               => true,
                    'is_verified'             => false,
                    'is_easypaisa_verified'   => ($epResult['resultCode'] === '0000'),
                    'easypaisa_verified_at'   => ($epResult['resultCode'] === '0000') ? now() : null,
                    'last_login_at'           => now(),
                ]
            );

            Log::info('SavingsEasypaisaController@register: customer upserted.', [
                'customer_id' => $customer->customer_id,
                'open_id'     => $userInfo['openId'],
                'mock'        => $usedMock,
            ]);

            // ── 6. Build response payload ─────────────────────────────────────
            return response()->json([
                'status'  => 200,
                'message' => 'Customer registered successfully.' . ($usedMock ? ' (mock data)' : ''),
                'mock'    => $usedMock,
                'data'    => $this->buildRegisterResponse($customer),
            ], 200);

        } catch (\Illuminate\Validation\ValidationException $e) {
            return response()->json([
                'status' => 422,
                'errors' => $e->errors(),
            ], 422);

        } catch (\Exception $e) {
            Log::error('SavingsEasypaisaController@register: Unexpected error.', [
                'message' => $e->getMessage(),
                'trace'   => $e->getTraceAsString(),
            ]);

            return response()->json([
                'status'  => 500,
                'message' => 'An unexpected error occurred.',
                'detail'  => $e->getMessage(),
            ], 500);
        }
    }

    // =========================================================================
    //  RESPONSE BUILDER
    // =========================================================================

    /**
     * Build the registration response with basic customer info only.
     * No plan/product/contribution data needed for the savings project.
     */
    private function buildRegisterResponse(SavingsCustomer $customer): array
    {
        return [
            'customer_id'            => $customer->customer_id,
            'full_name'              => $customer->full_name,
            'dob'                    => $customer->dob?->format('Y-m-d'),
            'open_id'     => $customer->open_id,
            'union_id'    => $customer->union_id,
            'gender'                 => $customer->gender,
            'msisdn'                 => $customer->msisdn,
            'is_easypaisa_verified'  => $customer->is_easypaisa_verified,
            'redirect_to'           => 'start_savings_page',
        ];
    }

    // =========================================================================
    //  PRIVATE HELPERS
    // =========================================================================

    private function fetchUserInfo(string $authCode): array
    {
        $requestTime = $this->nowKarachi();
        $endpoint    = '/v1/users/inquireUserInfo';
        $data        = ['authCode' => $authCode];

        $signatureString =
            "POST {$endpoint}\n" .
            "{$this->clientId}.{$requestTime}.{$this->accessToken}." .
            json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

        $signature = $this->generateSignature($signatureString);

        $headers = [
            'Content-Type' => 'application/json',
            'Client-Id'    => $this->clientId,
            'Request-Time' => $requestTime,
            'Access-Token' => $this->accessToken,
            'Signature'    => "algorithm=RSA2048, keyVersion=1, signature={$signature}",
        ];

        $url = $this->baseUrl . $endpoint;

        Log::info('Savings EP API Request', [
            'url'     => $url,
            'headers' => $headers,
            'body'    => $data,
        ]);

        $response = Http::withHeaders($headers)->post($url, $data);

        Log::info('Savings EP API Response', [
            'status'   => $response->status(),
            'response' => $response->body(),
        ]);

        $body = $response->json() ?? [];

        if (empty($body['userInfo'])) {
            Log::warning('SavingsEasypaisaController@fetchUserInfo: No userInfo in response — using mock data.', [
                'authCode'      => $authCode,
                'actual_status' => $response->status(),
                'actual_body'   => $body,
            ]);

            return [
                'body'    => $this->mockUserInfoResponse($authCode),
                'headers' => [],
                'status'  => 200,
                'mock'    => true,
            ];
        }

        return [
            'body'    => $body,
            'headers' => $response->headers(),
            'status'  => $response->status(),
            'mock'    => false,
        ];
    }

    private function mockUserInfoResponse(string $authCode): array
    {
        $seed    = abs(crc32($authCode));
        $msisdn  = '03' . str_pad($seed % 1000000000, 9, '0', STR_PAD_LEFT);
        $openId  = 'mock_open_'  . substr(md5($authCode), 0, 16);
        $unionId = 'mock_union_' . substr(md5($authCode . 'union'), 0, 16);

        return [
            'result' => [
                'resultCode'    => '0000',
                'resultStatus'  => 'S',
                'resultMessage' => 'SUCCESS (mock)',
            ],
            'userInfo' => [
                'openId'     => $openId,
                'unionId'    => $unionId,
                'authId'     => 'mock_auth_' . substr(md5($authCode . 'auth'), 0, 12),
                'userMsisdn' => $msisdn,
                'userName'   => 'Mock User',
                'userCnic'   => '3520212345671',
                'birthDate'  => '1990-01-01',
            ],
        ];
    }

    private function resolveDecryptedCnic(array $headers, ?string $encryptedCnic): ?string
    {
        $encryptHeader = $headers['encrypt'][0] ?? null;

        if (empty($encryptHeader) || empty($encryptedCnic)) {
            Log::warning('SavingsEasypaisaController: Cannot decrypt CNIC — missing encrypt header or value.', [
                'encrypt_header_present' => !empty($encryptHeader),
                'encrypted_cnic_present' => !empty($encryptedCnic),
            ]);
            return null;
        }

        $cryptoService = new EasypaisaCryptoService();
        $decrypted     = $cryptoService->decryptCnic($encryptHeader, $encryptedCnic);

        if ($decrypted) {
            Log::info('SavingsEasypaisaController: CNIC decrypted successfully.', [
                'preview' => substr($decrypted, 0, 5) . '**********',
            ]);
        } else {
            Log::error('SavingsEasypaisaController: CNIC decryption failed.');
        }

        return $decrypted;
    }

    private function deriveGender(?string $cnic): string
    {
        if (empty($cnic)) {
            return 'other';
        }

        $lastDigit = (int) substr($cnic, -1);

        return ($lastDigit % 2 !== 0) ? 'male' : 'female';
    }

    private function nowKarachi(): string
    {
        $date = new DateTime('now', new DateTimeZone('Asia/Karachi'));
        return $date->format('Y-m-d\TH:i:s.vP');
    }

    private function generateSignature(string $data): string
    {
        if (!$this->privateKey) {
            Log::error('SavingsEasypaisaController@generateSignature: Private key not loaded.');
            throw new \RuntimeException('Easypaisa private key is not configured.');
        }

        openssl_sign($data, $signature, $this->privateKey, OPENSSL_ALGO_SHA256);

        return urlencode(base64_encode($signature));
    }
}