<?php

namespace App\Services;

use Psr\Log\LoggerAwareTrait;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;

class ChargeAngelsApi
{
    use LoggerAwareTrait;
    private HttpClientInterface $client;
    private string $url;
    private string $tokenEndpoint;
    private string $email;
    private bool $acceptEula;
    private string $tenant;
    private string $password;


    public function __construct(
        HttpClientInterface $client,
        string $url,
        string $tokenEndpoint,
        string $email,
        string $password,
        bool $acceptEula,
        string $tenant
    ) {
        $this->client = $client;
        $this->url = $url;
        $this->tokenEndpoint = $tokenEndpoint;
        $this->email = $email;
        $this->acceptEula = $acceptEula;
        $this->tenant = $tenant;
        $this->password = $password;
    }

    public function request(string $method, string $uri,array $params=null): ResponseInterface
    {
        $message = '[Charge Angels Api] ';

        try {
            $token = $this->getToken();
            if (is_string($token)) {
                $borne = $this->client->request(
                    $method,
                    sprintf('%s%s', $this->url, $uri),
                    [
                        'auth_bearer' => $token,
                        'json'=>$params
                    ]
                );
                if (Response::HTTP_OK === $borne->getStatusCode()) {
                    return $borne;
                }

                $message .=  $borne->getContent();
            } else
                $message .= ' invalide token';

        }catch (\Exception $exception) {
            $message .= $exception->getMessage();
        }
        throw new \Exception($message);
    }

    /**
     * @return string|false
     * @throws ClientExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ServerExceptionInterface
     * @throws TransportExceptionInterface
     */
    public function getToken(): string|false
    {
        $message = 'erreur lors de la recuperation du token ';

        try {
            $response = $this->client->request(
                Request::METHOD_POST,
                sprintf('%s%s', $this->url, $this->tokenEndpoint),
                [
                    'json' => [
                        "email" => $this->email,
                        "password" => $this->password,
                        "acceptEula" => $this->acceptEula,
                        "tenant" => $this->tenant
                    ]
                ]
            );

            if (Response::HTTP_OK === $response->getStatusCode()
                && is_string($response->getContent())
                && ($tokenResponse = json_decode($response->getContent(), true))
                && (is_array($tokenResponse) && array_key_exists('token', $tokenResponse))
            ) {
                return $tokenResponse['token'];
            }
        } catch (\Exception $exception) {
            $message .= $exception->getMessage();
        }

        $this->logger->error($message, [
            'email' => $this->email,
            'acceptEula' => $this->acceptEula,
            'tenant' => $this->tenant,
        ]);

        return false;
    }

    /**
     * @param string $borneId
     * @param string $connectorId
     * @return string
     * @throws ClientExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ServerExceptionInterface
     * @throws TransportExceptionInterface
     */
    public function getPriceFromApi(string $borneId, string $connectorId){
        $response = array();
        try {
            $priceResponse = $this->request(
                Request::METHOD_GET,
                sprintf(
                    'api/pricing-model/resolve?ChargingStationID=%s&ConnectorID=%d',
                    $borneId,
                    $connectorId
                )
            );
            if ($priceResponse->getStatusCode() === Response::HTTP_OK) {
                return json_decode($priceResponse->getContent());
            }

        }catch(\Exception $exception){
            return $exception->getMessage();
        }
        return null;
    }
    public function getBorneId(){
        try{
            $init = $this->request( Request::METHOD_GET,  'api/charging-stations');
            if ($init->getStatusCode() === Response::HTTP_OK) {
                return json_decode($init->getContent());
            }
        }catch(\Exception $exception){
            return $exception->getMessage();
        }
        return null;
    }
    public function startCharge(string $idBorne,string  $connectorId,string $tagId="123456",string $visualTagID="123456-123456"){
        //TODO remove force values
        $tagId="123456";
        $visualTagID="123456-123456";
        // End force Value---------------------------------
        $params=[
            "chargingStationID"=>$idBorne,
            "args"=> [
                "tagID"=> $tagId,
                "visualTagID"=> $visualTagID,
                "connectorId"=> $connectorId
            ]
        ];
        try{
            $init = $this->request( Request::METHOD_PUT,  'api/transactions/start',$params);
            if ($init->getStatusCode() === Response::HTTP_OK) {
                return json_decode($init->getContent());
            }
        }catch(\Exception $exception){
            return $exception->getMessage();
        }
        return null;
    }
    public function stopCharge(string $transaction)
    {
        try{
            $stop = $this->request( Request::METHOD_PUT, "api/transactions/$transaction/stop");
            if ($stop->getStatusCode() === Response::HTTP_OK) {
                return json_decode($stop->getContent());
            }
        }catch(\Exception $exception){
            return $exception->getMessage();
        }
        return null;
    }
    public function infoCharge(string $transaction)
    {
        try{
            $stop = $this->request( Request::METHOD_GET, "api/transactions/$transaction");
            if ($stop->getStatusCode() === Response::HTTP_OK) {
                return $stop->toArray();
            }
        }catch(\Exception $exception){
            return $exception->getMessage();
        }
        return null;
    }
}
