<?php

namespace App\Libs\Services;

use Exception;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Twintag;
use TwintagCompany;

class TwintagSyncService
{
    const API_BASE_URL = 'https://admin.twintag.io/api/v1';
    const TAGS_ENDPOINT_PATH = '/twintags?include=downloadView&include=metadata';
    const COMPANIES_ENDPOINT_PATH = '/data/company';

    protected $client;

    public function __construct()
    {
        $this->client = new Client([
            'base_uri' => self::API_BASE_URL,
            'headers' => [
                'Authorization' => 'Bearer ' . config('app.twintagAPI.key')
            ]
        ]);
    }

    public function syncTwintags(bool $force = false)
    {
        Log::info('Syncing Twintags...');

        $tags = $this->getTwintags();

        Log::info('Got ' . sizeof($tags) . ' tags to sync.');

        $count = 0;
        $foundExtIds = [];
        foreach ($tags as $tag) {
            if ($this->syncTwintag($tag, $force)) {
                $foundExtIds[] = $tag['included']['metadata']['id'];
                $count ++;
            }
        }

        // Delete tags that are not present anymore
        Twintag::whereNotIn('ext_id', $foundExtIds)->delete();

        Log::info('Twintag Sync complete. ' . $count . ' tags synced.');
    }

    protected function syncTwintag(array $data, bool $force = false)
    {
        try {
            $extId =  $data['included']['metadata']['id'];
            $meta = $data['included']['metadata'];
            $download = $data['included']['downloadView'];
            $twintag = Twintag::where('ext_id', $extId)->first();
            $company = TwintagCompany::where('ext_id', $meta['vatNumber'])->first();

            if (!$company) {
                Log::warning('Unable to sync Twintag with metadata id ' . $extId . ': Company not found - ' . $meta['vatNumber']);
                return false;
            }

            if ($company->ext_id == 'BE000000000') {
                Log::info('Skipping twintag (Company VAT ID = BE000000000)');
                return false;
            }

            if ($meta['expired']) {
                if ($twintag) {
                    $twintag->delete();
                }
                return true;
            }

            if (!$twintag) {
                $twintag = new Twintag();
                $twintag->ext_id = $extId;
                $twintag->twintag_company_id = $company->id;
                $twintag->save();
            }

            if (!$force && $meta['$timestamp'] == $twintag->timestamp) {
                return true;
            }

            $twintag->link_url = $download['$uri'];
            $twintag->type = trim($meta['type']);
            $twintag->level = trim($meta['level']);
            $twintag->timestamp = trim($meta['$timestamp']);
            $twintag->save();

            return $twintag;
        } catch (Exception $e) {
            Log::error('Error while creating / updating twintag. ' . $e->getMessage());
            return false;
        }
    }

    public function syncCompanies(bool $force = false)
    {
        Log::info('Syncing Twintag Companies...');

        $companies = $this->getCompanies();

        Log::info('Got ' . sizeof($companies) . ' companies to sync.');

        $count = 0;
        foreach ($companies as $company) {
            $count += $this->syncCompany($company, $force) ? 1 : 0;
        }

        Log::info('Twintag Companies Sync complete. ' . $count . ' companies synced.');
    }

    protected function syncCompany(array $data, bool $force = false)
    {
        try {
            $company = TwintagCompany::where('ext_id', $data['vatNumber'])->first();

            if (!$company) {
                $company = new TwintagCompany();
                $company->ext_id = $data['vatNumber'];
                $company->save();
            }

            if (!$force && $data['$timestamp'] == $company->timestamp) {
                return true;
            }

            $company->name = $data['name'];

            if ($company->logo_local_filename) {
                Storage::delete(config('path.internal.media') .'/' . $company->logo_local_filename);
                $company->logo_local_filename = null;
                $company->logo_filename = null;
            }

            if (!empty($data['logo']['URL'])) {
                $destFilename = random_string() . $data['logo']['Extention'];

                $downloadSuccess = copy($data['logo']['URL'], Storage::path(config('path.internal.media') .'/' . $destFilename));

                if ($downloadSuccess) {
                    $company->logo_local_filename = $destFilename;
                    $company->logo_filename = $data['logo']['Name'];
                }
            }

            $company->timestamp = $data['$timestamp'];
            $company->save();

            return $company;
        } catch (Exception $e) {
            Log::error('Error while creating / updating twintag.' . $e->getMessage());
            return false;
        }
    }

    protected function getTwintags()
    {
        $res = $this->client->request('GET', self::API_BASE_URL . self::TAGS_ENDPOINT_PATH);

        if ($res->getStatusCode() !== 200) {
            throw new \Exception('Error retrieving twintags list from API', $res->getReasonPhrase());
        }
        $data = json_decode($res->getBody(), true);

        return $data['pagedData'];
    }

    protected function getCompanies()
    {
        $res = $this->client->request('GET', self::API_BASE_URL . self::COMPANIES_ENDPOINT_PATH);

        if ($res->getStatusCode() !== 200) {
            throw new \Exception('Error retrieving companies list from API', $res->getReasonPhrase());
        }
        $data = json_decode($res->getBody(), true);

        return $data;
    }
}
