<?php

namespace Gaco\SnapBi;

use Gaco\SnapBi\Services\VirtualAccountService;
use Gaco\SnapBi\Services\TokenService;
use Gaco\SnapBi\Services\Config as ConfigManager;
use Gaco\SnapBi\Services\BankManager;
use Gaco\SnapBi\Enums\ServiceCode;
use Gaco\SnapBi\Contracts\ServiceInterface;
use Gaco\SnapBi\Contracts\ConfigInterface;
use Gaco\SnapBi\Exceptions\SnapBiException;

class SnapBi
{
    /**
     * Current bank config instance
     */
    protected ?ConfigInterface $config = null;

    /**
     * Current bank name
     */
    protected ?string $bankName = null;

    /**
     * Current bank service instance (when using bank-specific services)
     */
    protected ?ServiceInterface $bankService = null;

    /**
     * Constructor
     * 
     * @param string|null $bankName Bank name (ocbc, bca, mandiri, etc.)
     */
    public function __construct(?string $bankName = null)
    {
        if ($bankName) {
            $this->setBank($bankName);
        }
    }

    /**
     * Set bank and load config
     * 
     * @param string $bankName
     * @return self
     */
    public function setBank(string $bankName): self
    {
        $this->bankName = strtolower($bankName);
        $this->config = ConfigManager::for($this->bankName);

        // Check if config is registered
        $configClass = get_class($this->config);
        if (!$configClass::isRegistered()) {
            throw new SnapBiException(
                "Configuration for bank '{$bankName}' is not registered. " .
                    "Please register it first using: ConfigManager::{$bankName}([...])"
            );
        }

        // Get bank-specific service instance
        $this->bankService = BankManager::for($this->bankName, $this->config);

        return $this;
    }

    /**
     * Get current bank config
     * 
     * @return ConfigInterface|null
     */
    public function getConfig(): ?ConfigInterface
    {
        return $this->config;
    }

    /**
     * Get current bank name
     * 
     * @return string|null
     */
    public function getBankName(): ?string
    {
        return $this->bankName;
    }

    /**
     * Static method to get bank instance
     * Example: SnapBi::ocbc() or SnapBi::for('ocbc')
     * 
     * @param string $bankName
     * @return self
     */
    public static function for(string $bankName): self
    {
        return new self($bankName);
    }

    /**
     * Magic static method to get bank instance
     * Example: SnapBi::ocbc()
     * 
     * @param string $method Bank name
     * @param array $args
     * @return self
     */
    public static function __callStatic(string $method, array $args = []): self
    {
        return self::for($method);
    }
    /**
     * Get Inquiry service
     */
    public function inquiry(): ServiceInterface
    {
        if ($this->bankService) {
            return $this->bankService->inquiry();
        }

        return new VirtualAccountService(ServiceCode::INQUIRY, $this->config);
    }

    /**
     * Get Transfer service
     */
    public function transfer(): ServiceInterface
    {
        if ($this->bankService) {
            return $this->bankService->transfer();
        }

        return new VirtualAccountService(ServiceCode::TRANSFER_INQUIRY, $this->config);
    }

    /**
     * Get Payment service
     */
    public function payment(): ServiceInterface
    {
        if ($this->bankService) {
            return $this->bankService->payment();
        }

        return new VirtualAccountService(ServiceCode::PAYMENT, $this->config);
    }

    /**
     * Get Token service (B2B Access Token)
     */
    public function token(): ServiceInterface
    {
        if ($this->bankService) {
            return $this->bankService->token();
        }

        return new TokenService($this->config);
    }

    /**
     * Get Update Status VA service
     */
    public function updateStatusVa(): ServiceInterface
    {
        if ($this->bankService) {
            return $this->bankService->updateStatusVa();
        }

        return new VirtualAccountService(ServiceCode::UPDATE_STATUS_VA, $this->config);
    }

    /**
     * Get Inquiry Status service
     */
    public function inquiryStatus(): ServiceInterface
    {
        if ($this->bankService) {
            return $this->bankService->inquiryStatus();
        }

        return new VirtualAccountService(ServiceCode::INQUIRY_STATUS, $this->config);
    }

    /**
     * Get Notify Payment Intrabank service
     */
    public function notifyPaymentIntrabank(): ServiceInterface
    {
        if ($this->bankService) {
            return $this->bankService->notifyPaymentIntrabank();
        }

        return new VirtualAccountService(ServiceCode::NOTIF_PAYMENT_INTRABANK, $this->config);
    }

    /**
     * Get Header utilities for response headers
     * 
     * @return \Gaco\SnapBi\Services\Header
     */
    public function header(): \Gaco\SnapBi\Services\Header
    {
        return new \Gaco\SnapBi\Services\Header($this->config);
    }

    /**
     * Get Signature utilities for signature creation and verification
     * 
     * @return \Gaco\SnapBi\Services\Signature
     */
    public function signature(): \Gaco\SnapBi\Services\Signature
    {
        return new \Gaco\SnapBi\Services\Signature($this->config);
    }
}
