<?php

namespace App\Services\Asset;

use Exception;
use App\Models\Asset;
use App\Models\AssetStatus;
use App\Models\ApiCredential;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
use App\Http\Traits\Asn\AsnPresidioTrait;

class AsnPresidioIntegration
{
    use AsnPresidioTrait;

    protected $baseUrl;
    protected $userName;
    protected $password;
    protected $credential;

    /**
     * Get the API credentials with caching
     */
    protected function getCredentials()
    {
        $this->credential   = ApiCredential::whereSlug('asn_presidio')->first();

        $this->baseUrl  = $this->credential->url ?? '';
        $this->userName = $this->credential->user_name ?? '';
        $this->password = $this->credential->password ?? '';
    }


    /**
     * Retrieves the 'presidio_in_transit' asset status with caching.
     *
     * @return mixed The 'presidio_in_transit' asset status.
     */
    protected function getInTransitStatus()
    {
        return Cache::remember('asset_status:presidio_in_transit', 3600, function () {
            AssetStatus::where('slug', 'presidio_in_transit')->first();
        });
    }

    /**
     * Check the API is connected or not
     */
    public function checkConnection()
    {
        $this->getCredentials();
        $authCode = $this->getAuthCode();

        if ($authCode === false) {
            return false;
        }

        try {

            $response = Http::withHeaders([
                'User-Agent'   => 'ProcurementAPI/1.0(custom;teqtivity)',
                'Content-Type' => 'application/json'
            ])->withToken($authCode)
                ->retry(3, 3000)
                ->get($this->baseUrl . 'api/v1/assets?pageLimit=1')
                ->throw();

            return $response->successful();
        } catch (Exception $e) {

            Log::channel('daily')->info("ASN Presidio Connection Error :- " . $e->getMessage());
            return false;
        }
    }

    /**
     * Get the Authorization code
     */
    public function getAuthCode()
    {
        try {

            $this->getCredentials();
            $response = Http::withHeaders([
                'User-Agent' => 'ProcurementAPI/1.0(custom;teqtivity)'
            ])->acceptJson()
                ->withBody(json_encode([
                    'password' => $this->password,
                    'username' => $this->userName,
                ]), 'application/json')
                ->post($this->baseUrl . 'auth/token')
                ->throw()
                ->json();

            if ($response) {
                ApiCredential::where('slug', 'asn_presidio')->update(['data' => json_encode($response)]);
                return $response['access_token'] ?? false;
            }
        } catch (Exception $e) {

            Log::channel('daily')->info("ASN Presidio Error :- " . $e->getMessage());
            return false;
        }
    }

    /**
     * Get the Order Details from given date to current date
     */
    public function getOrders($startDate, $endDate, $pageNumber = 1)
    {
        $authCode = $this->getAuthCode();

        if ($authCode === false) {
            return false;
        }

        try {
            $this->getCredentials();
            $response = Http::withHeaders([
                'User-Agent'   => 'ProcurementAPI/1.0(custom;teqtivity)',
                'Content-Type' => 'application/json'
            ])->withToken($authCode)
                ->retry(3, 3000)
                ->timeout(60)
                ->get($this->baseUrl . "api/v1/assets/interval?endDate=" . $endDate .
                    "&pageLimit=1000&pageNumber=" . $pageNumber . "&startDate=" . $startDate)
                ->throw()
                ->json();

            return $response ?? null;
        } catch (Exception $e) {
            Log::channel('daily')->info("Presidio API Error :- " . $e->getMessage());
        }

        return false;
    }

    /**
     * Save assets from Presidio response data
     */
    public function importPresidioDetails($orders)
    {
        if (!$orders) {
            return 0;
        }

        $totalSavedAssets = 0;

        foreach ($orders as $order) {
            $totalSavedAssets += $this->saveAssetDetails($order);
        }

        return $totalSavedAssets;
    }

    /**
     * Process the Presidio API response and save the assets
     */
    public function saveAssetDetails($item)
    {
        $counter = 0;
        $data = $this->generatePresidioData($item);

        if ($this->validateItem($data)) {

            $asset = Asset::create($data);
            $this->createAssetHistory($asset, $this->getInTransitStatus()->id);
            $counter++;
        }

        return $counter;
    }

    /**
     * Generate Array for saving data
     */
    public function generatePresidioData($item)
    {
        $assetData = [];

        if ($this->isAccessories($item) || $this->isUnwantedPart($item)) {

            return $assetData;
        }

        $assetData = $this->getHardwareDetails($item);

        $assetData['po_id']                 = $item['customerPONumber'] ? trim($item['customerPONumber']) : '';
        $assetData['serial_no']             = $this->getSerialNumber($item, $assetData);
        $assetData['asset_tag']             = $item['additionalReference'] ?? $assetData['serial_no'];
        $assetData['asset_status_id']       = $this->getInTransitStatus()->id ?? '';
        $assetData['description']           = $item['itemCode'] ? trim($item['itemCode']) : '';
        $assetData['asset_original_value']  = $item['unitSellingPrice'] ?? null;
        $assetData['asn_dispatch_city']     = $item['despatchCity'] ?? null;

        return $assetData;
    }
}
