<?php

namespace App\Service;

use League\Csv\Reader;
use League\Csv\Writer;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Contracts\HttpClient\HttpClientInterface;

class Openalex
{
    private $client;
    private $id;

    public function __construct()
    {
        $this->client = HttpClient::create();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function setId(int $id): self
    {
        $this->id = $id;
        return $this;
    }

    public function run(string $filename='file.csv'){
        $writer = Writer::createFromPath($filename, 'w+');
        $i = 0;
        $next = '*';
        do {
            $next = $this->traitement($next,$writer);
        } while (!is_null($next));
    }

    private function traitement($next,$writer)
    {
        $exclude = ['abstract_inverted_index','concepts','authorships','alternate_host_venues','referenced_works','related_works','is_paratext','biblio','is_authors_truncated'];
        $doSplit = ['open_access','host_venue'];
        $ret = $this->fetchOpenAlexAPI("https://api.openalex.org/works?filter=institutions.ror:https://ror.org/00afp2z80|https://ror.org/00bmzhb16|https://ror.org/044s61914,type:article,publication_year:2018|2019|2020&per-page=200&cursor=".$next);
        foreach ($ret['results'] as $key => $value)
        {
            $this->setId($key);
            $ret['results'][$key]['abstract'] = $this->parseAbstractInvertedIndex($ret['results'][$key]['abstract_inverted_index']);   
            foreach ($value as $key2 => $value2) {
                if (in_array($key2,$exclude)) {
                    unset($ret['results'][$key][$key2]);
                } else if (is_array($value2) && in_array($key2,$doSplit)) {
                    unset($ret['results'][$key][$key2]);
                    if(strcmp('host_venue', $key2) === 0 ){
                        if(is_null($value2['issn'])){
                            $value2['issn']=array('','');
                        } else if(count($value2['issn']) < 2 ){
                            $value2['issn'][1]='';
                        } else if(count($value2['issn']) > 2){
                            $value2['issn'] = array_slice($value2['issn'], 0, 2);  
                        }
                    }
                    $input = $this->array_flat($value2, $key2);
                    $ret['results'][$key] = array_merge($ret['results'][$key], $input);
                } else if (is_array($value2) && !in_array($key2,$doSplit)) {
                    $input = $this->array_flat($value2, $key2);
                    $ret['results'][$key][$key2] = implode('||', array_map(
                        function ($v, $k) { return sprintf("%s='%s'", $k, $v); },
                        $input,
                        array_keys($input)
                    ));
                }
            }
        }
        $writer->insertAll($ret['results']);
        return $ret['meta']['next_cursor'];
    }

    private function fetchOpenAlexAPI(string $url): array
    {
        $response = $this->client->request(
            'GET',
            $url
        );

        $statusCode = $response->getStatusCode();
        $contentType = $response->getHeaders()['content-type'][0];
        $content = $response->toArray();
        return $content;
    }

    private function array_flat($array, $prefix = '')
    {
        $result = array();
        foreach ($array as $key => $value)
        {
            $new_key = $prefix . (empty($prefix) ? '' : '.') . $key;

            if (is_array($value))
            {
                $result = array_merge($result, $this->array_flat($value, $new_key));
            }
            else
            {
                $result[$new_key] = $value;
            }
        }
        return $result;
    }

    private function parseAbstractInvertedIndex(?array $abstract)
    {
        $abstractArray = null;
        if(!is_null($abstract) && !empty($abstract)){
            foreach ($abstract as $key => $value)
            {
                foreach ($value as $val)
                {
                    $abstractArray[$val] = $key;
                }
            }
            if(ksort($abstractArray)){
                return implode(' ',$abstractArray);
            }
        }
        return null;
    }
}