<?php

class Converter {

    private ?array $currencies;
    private ?float $amount = null;
    private ?string $from = null;
    private ?string $to = null;

    private array $conversion = [];
    
    public function __construct( ?int $userid = null, $mode = 'from' ) {
        $this->currencies = Uss::$global['options']->get('bank:currencies');
        $this->autoFill( $userid, strtolower($mode) );
    }

    public function amount( float $amount ) {
        $this->amount = $amount;
        return $this;
    }

    public function from( string $currency ) {
        $this->from = $this->validateCurrency($currency);
        return $this;
    }

    public function to( string $currency ) {
        $this->to = $this->validateCurrency($currency);
        return $this;

    }

    public function convert() {
        $this->validateRequest();
        $fromUnit = $this->get($this->from, 'rate');
        $this->conversion['from:USD'] = ( 1 / $fromUnit );
        $this->conversion['fromAmount:USD'] = $this->conversion['from:USD'] * $this->amount;
        $this->conversion['result'] = $this->conversion['fromAmount:USD'] * $this->get($this->to, 'rate');
        return $this->resultant();
    }

    private function autoFill( ?int $userid, string $mode ) {
        if( is_null($userid) ) return;
        if( !in_array($mode, ['from', 'to']) ) {
            throw new Exception( __CLASS__ . "::__constructor # (argument 2) mode must either be 'from' or 'to'" );
        };
        $bankinfo = Uss::$global['usermeta']->get('bank:info', $userid);
        $currency = $bankinfo['system']['currency'];
        if( !empty($currency) ) $this->{$mode}( $currency );
    }

    private function validateCurrency( string $currency ) {
        $currency = strtoupper(trim($currency));
        $currencyCodes = array_column($this->currencies, 'code');
        if( !in_array($currency, $currencyCodes) ) {
            $currency = 'USD';
        };
        return $currency;
    }

    private function validateRequest() {
        foreach( ["from", "to", "amount"] as $prop ) {
            if( is_null($this->{$prop}) ) {
                throw new Exception( __CLASS__ . "::{$prop}() method must be called to supply relevant information" );
            };
        }
    }

    private function get( string $code, ?string $key = null ) {
        foreach( $this->currencies as $currency ) {
            if( $currency['code'] == $code ) {
                if( !is_null($key) ) {
                    $value = $currency[ $key ] ?? null;
                    if( $key == 'rate' ) $value = (float)$value;
                    return $value;
                };
                return $currency;
            };
        };
    }

    private function resultant() {
        $currency = new stdClass();
        $currency->code = $this->to;
        $currency->name = $this->get( $this->to, 'name' );
        $currency->symbol = $this->get( $this->to, 'symbol' );
        $currency->amount = $this->conversion['result'];
        return $currency;
    }

};