<?php

namespace App\Controllers;

use CodeIgniter\RESTful\ResourceController;
use App\Libraries\YemscanService;
use App\Models\YemTransactionModel;

/**
 * Simplified YEMScan / YEMChain API endpoints.
 * Base URL: api/yemscan/
 * Auth is server-side via env (yemscan.api_key, yemscan.custom_domain, yemscan.uid).
 */
class Yemscan extends ResourceController
{
    protected $yemscanService;
    protected $yemTransactionModel;

    public function __construct()
    {
        $this->yemscanService = new YemscanService();
        $this->yemTransactionModel = new YemTransactionModel();
    }

    /**
     * Normalize hash to 0x-prefixed form.
     */
    private function normalizeHash(string $hash): string
    {
        $hash = trim($hash);
        if ($hash === '') {
            return $hash;
        }
        return strpos($hash, '0x') === 0 ? $hash : '0x' . $hash;
    }

    /**
     * POST /api/yemscan/transactions (or /api/yemscan/transaction)
     * Body: single transaction object or { "transactions": [ ... ] } (max 100).
     */
    public function createTransactions()
    {
        $json = $this->request->getJSON(true);
        if ($json === null) {
            $json = [];
        }

        $transactions = [];
        if (isset($json['transactions']) && is_array($json['transactions'])) {
            $transactions = $json['transactions'];
        } elseif (isset($json['from_uid'], $json['to_uid'], $json['value'], $json['reason'], $json['asset'], $json['from_curr'], $json['to_curr'])) {
            $transactions = [$json];
        }

        if (empty($transactions)) {
            return $this->respond([
                'success' => false,
                'message' => 'Provide a transaction object or transactions array with from_uid, to_uid, value, reason, asset, from_curr, to_curr',
            ], 400);
        }

        $result = $this->yemscanService->createTransactions($transactions);
        if ($result['success'] && !empty($result['transaction_hashes'])) {
            $hashes = $result['transaction_hashes'];
            foreach ($hashes as $i => $hash) {
                $tx = $transactions[$i] ?? null;
                if ($tx && $hash) {
                    $value = isset($tx['value']) && is_numeric($tx['value']) ? (float) $tx['value'] : 0;
                    $this->yemTransactionModel->insert([
                        'hash'       => $hash,
                        'from_uid'  => (int) ($tx['from_uid'] ?? 0),
                        'to_uid'    => (int) ($tx['to_uid'] ?? 0),
                        'value'     => $value,
                        'reason'    => $tx['reason'] ?? null,
                        'asset'     => $tx['asset'] ?? 'YEM',
                        'from_curr' => $tx['from_curr'] ?? null,
                        'to_curr'   => $tx['to_curr'] ?? null,
                        'status'    => 'pending',
                        'created_at'=> date('Y-m-d H:i:s'),
                    ]);
                }
            }
        }
        return $this->respond($result, $result['success'] ? 200 : 400);
    }

    /**
     * GET /api/yemscan/balances?uids=123,456&tokenSymbol=YEM
     */
    public function getBalances()
    {
        $uidsStr = $this->request->getGet('uids');
        if ($uidsStr === null || $uidsStr === '') {
            return $this->respond([
                'success' => false,
                'message' => 'uids required (comma-separated)',
            ], 400);
        }
        $uids = array_filter(array_map('intval', explode(',', $uidsStr)));
        $tokenSymbol = $this->request->getGet('tokenSymbol') ?? 'YEM';

        $result = $this->yemscanService->getBalances($uids, $tokenSymbol);
        return $this->respond($result, $result['success'] ? 200 : (isset($result['error_code']) && $result['error_code'] === 403 ? 403 : 400));
    }

    /**
     * GET /api/yemscan/globals
     */
    public function getGlobals()
    {
        $result = $this->yemscanService->getGlobals();
        return $this->respond($result, $result['success'] ? 200 : (isset($result['error_code']) && $result['error_code'] === 403 ? 403 : 400));
    }

    /**
     * GET /api/yemscan/volume?tokenSymbol=YEM
     */
    public function getVolume()
    {
        $tokenSymbol = $this->request->getGet('tokenSymbol') ?? 'YEM';
        $result = $this->yemscanService->getTransactionVolume($tokenSymbol);
        return $this->respond($result, $result['success'] ? 200 : (isset($result['error_code']) && $result['error_code'] === 403 ? 403 : 400));
    }

    /**
     * GET /api/yemscan/transaction-statuses?hashes=0xabc,0xdef
     */
    public function getTransactionStatuses()
    {
        $hashesStr = $this->request->getGet('hashes');
        if ($hashesStr === null || $hashesStr === '') {
            return $this->respond([
                'success' => false,
                'message' => 'hashes required (comma-separated)',
            ], 400);
        }
        $hashes = array_filter(array_map('trim', explode(',', $hashesStr)));
        $includeDetails = $this->request->getGet('include_details') === '1' || $this->request->getGet('include_details') === 'true';

        $result = $this->yemscanService->getTransactionStatuses($hashes, $includeDetails);
        return $this->respond($result, $result['success'] ? 200 : (isset($result['error_code']) && $result['error_code'] === 403 ? 403 : 400));
    }

    /**
     * GET /api/yemscan/asset-stats?tokenSymbol=YEM
     */
    public function getAssetStats()
    {
        $tokenSymbol = $this->request->getGet('tokenSymbol') ?? 'YEM';
        $result = $this->yemscanService->getAssetStats($tokenSymbol);
        return $this->respond($result, $result['success'] ? 200 : (isset($result['error_code']) && $result['error_code'] === 403 ? 403 : 400));
    }

    /**
     * GET /api/yemscan/public-key/{uid} or ?uid=123
     */
    public function getPublicKey($uid = null)
    {
        if ($uid === null || $uid === '') {
            $uid = $this->request->getGet('uid');
        }
        if ($uid === null || $uid === '') {
            return $this->respond([
                'success' => false,
                'message' => 'uid required (path or query)',
            ], 400);
        }
        $result = $this->yemscanService->getPublicKey((int) $uid);
        return $this->respond($result, $result['success'] ? 200 : (isset($result['error_code']) && $result['error_code'] === 403 ? 403 : 404));
    }

    /**
     * GET /api/yemscan/transaction/{hash} or ?hash=0x...
     */
    public function getTransaction($hash = null)
    {
        if ($hash === null) {
            $hash = $this->request->getGet('hash');
        }
        if ($hash === null || $hash === '') {
            return $this->respond([
                'success' => false,
                'message' => 'hash required (path or query)',
            ], 400);
        }
        $result = $this->yemscanService->getTransaction($hash);
        return $this->respond($result, $result['success'] ? 200 : (isset($result['error_code']) && $result['error_code'] === 403 ? 403 : 404));
    }

    /**
     * GET /api/yemscan/transaction/verify or transaction/{hash}/verify
     * Query: expected_amount, expected_to_uid.
     */
    public function verifyTransaction($hash = null)
    {
        if ($hash === null) {
            $hash = $this->request->getGet('hash');
        }
        if ($hash === null || $hash === '') {
            return $this->respond([
                'success' => false,
                'message' => 'hash required (path or query)',
            ], 400);
        }
        $expectedAmount = $this->request->getGet('expected_amount');
        $expectedToUid = $this->request->getGet('expected_to_uid');
        $normalizedHash = $this->normalizeHash((string) $hash);
        $result = $this->yemscanService->verifyTransaction(
            $hash,
            $expectedAmount !== null && $expectedAmount !== '' ? (float) $expectedAmount : null,
            $expectedToUid !== null && $expectedToUid !== '' ? (int) $expectedToUid : null
        );

        // Keep local recorded status in sync for consumer verify workflows (same vocabulary as YEMScan).
        if (!empty($result['success'])) {
            if (!empty($result['verified'])) {
                $this->yemTransactionModel->updateStatusByHash($normalizedHash, 'confirmed');
            } elseif (($result['status'] ?? '') === 'failed') {
                $this->yemTransactionModel->updateStatusByHash($normalizedHash, 'failed');
            }
        }

        return $this->respond($result, 200);
    }

    /**
     * GET /api/yemscan/uid or /api/yemscan/uid?pernum=1001296648
     * Returns UID from pernum: uid = pernum - 1000000000.
     * With no query param: returns this app's UID (from configured yemscan.pernum).
     * With pernum=...: returns the UID for that pernum so consumers can resolve their own.
     */
    public function getUid()
    {
        $pernum = $this->request->getGet('pernum');
        $result = $this->yemscanService->getUidFromPernum($pernum !== null && $pernum !== '' ? $pernum : null);
        return $this->respond($result, $result['success'] ? 200 : 400);
    }

    /**
     * GET /api/yemscan/validate-access?uid=789&platform_name=FinFlo
     * Validates whether the given UID is allowed to access the platform (e.g. FinFlo).
     * Call when user opens the app with a stored Pernum/UID or when they add their Pernum.
     */
    public function validateAccess()
    {
        $uid = $this->request->getGet('uid');
        if ($uid === null || $uid === '') {
            return $this->respond([
                'success' => false,
                'access_granted' => false,
                'message' => 'uid required (query parameter)',
            ], 400);
        }
        $uidInt = (int) (is_string($uid) ? preg_replace('/[^0-9-]/', '', $uid) : $uid);
        if ($uidInt === 0 && $uid !== '0' && $uid !== 0) {
            return $this->respond([
                'success' => false,
                'access_granted' => false,
                'message' => 'Invalid uid',
            ], 400);
        }
        $platformName = $this->request->getGet('platform_name');
        $platformName = $platformName !== null && $platformName !== '' ? $platformName : null;

        $result = $this->yemscanService->validateThirdPartyAccess($uidInt, $platformName);
        return $this->respond($result, 200);
    }

    /**
     * GET /api/yemscan/health
     */
    public function health()
    {
        if (!$this->yemscanService->isConfigured()) {
            return $this->respond([
                'success' => false,
                'message' => 'YEMScan not configured (check yemscan.api_key, yemscan.custom_domain, yemscan.uid)',
            ], 503);
        }
        $result = $this->yemscanService->getGlobals();
        if ($result['success']) {
            return $this->respond([
                'success' => true,
                'message' => 'YEMScan API OK',
                'configured' => true,
            ], 200);
        }
        return $this->respond([
            'success' => false,
            'message' => $result['message'] ?? 'YEMScan API unreachable',
            'configured' => true,
        ], 503);
    }

    /**
     * GET /api/yemscan/cron/refresh-statuses?key=...&limit=100
     * URL-based cron endpoint for syncing pending YEM statuses.
     */
    public function cronRefreshStatuses()
    {
        $cronKey = trim((string) env('yemscan.cron_key', ''));
        if ($cronKey === '') {
            return $this->respond([
                'success' => false,
                'message' => 'Cron key not configured. Set yemscan.cron_key in .env',
            ], 503);
        }

        $providedKey = (string) ($this->request->getGet('key') ?? '');
        if ($providedKey === '' || !hash_equals($cronKey, $providedKey)) {
            return $this->respond([
                'success' => false,
                'message' => 'Unauthorized',
            ], 401);
        }

        if (! $this->yemscanService->isConfigured()) {
            return $this->respond([
                'success' => false,
                'message' => 'YEMScan is not configured',
            ], 503);
        }

        $limit = (int) ($this->request->getGet('limit') ?? 100);
        $limit = max(1, min(100, $limit));

        try {
            $updated = $this->yemTransactionModel->refreshStatuses($this->yemscanService, $limit);
            return $this->respond([
                'success' => true,
                'message' => 'YEM pending statuses refreshed',
                'updated' => $updated,
                'limit' => $limit,
                'checked_at' => date('Y-m-d H:i:s'),
            ], 200);
        } catch (\Throwable $e) {
            log_message('error', 'YEM cron refresh failed: ' . $e->getMessage());
            return $this->respond([
                'success' => false,
                'message' => 'Refresh failed',
            ], 500);
        }
    }
}
