<?php


namespace App\Libs\Import;

use App\Exceptions\ImportException;
use App\Facades\Services\ImportService;
use App\Facades\Services\CleanImportService;
use App\Libs\Security\XSSCleanFilter;
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\HandlerStack;
use GuzzleRetry\GuzzleRetryMiddleware;
use Illuminate\Support\Facades\DB;
use Waavi\Sanitizer\Sanitizer;
use Misd\Linkify\Linkify;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Log;
use RequestContext;
use Embed\Embed;
use Throwable;
use Exception;

class Import
{
    private $endpoint = '';
    private $type = '';
    private $availableLanguages = [
        'pt', 'en'
    ];
    private $parseLanguages = [
        'English' => 'en',
    ];
    private $defaultLanguage = 'pt';
    private $filters = [
        'xss_clean',
        'trim'
    ];
    private $allowedTags = '<b><i><a><br>';
    private $allowedTagsWithSup = '<b><i><a><br><sup>';
    private $customFilters = [];
    private $linkify;
    private $typesToClean = [];

    public function __construct(string $type = '', $types)
    {
        $this->stack = HandlerStack::create();
        $this->stack->push(GuzzleRetryMiddleware::factory([
            'retry_on_status' => [
                503,
                429,
                404,
                500
            ],
            'max_retry_attemps' => 10,
            'on_retry_callback' => function () {
                Log::channel('importLogStack')->info('Oops, something happened! Retrying...');
            }
        ]));
        $this->endpoint = config('import.endpoint');
        $this->type = $type;
        $this->client = new Client([
            'handler' => $this->stack,
            'base_uri' => $this->endpoint,
            'verify' => false
        ]);

        // $this->client->setDefaultOption('verify', false);

        $this->customFilters = [
            'xss_clean' => XSSCleanFilter::class
        ];
        $this->typesToClean = $types;
    }

    public function start()
    {
        switch ($this->type) {
            case 'Themes':
                $this->_getTaxonomy('import.themes', 'Theme', 'Tema', 'SubTema');
                break;
            case 'Typologies':
                $this->_getTaxonomy('import.typologies', 'Typology', 'Tipologia', 'SubTipologia');
                break;
            case 'Locations':
                $this->_getTaxonomy('import.locations', 'Location', 'Local', 'SubLocal');
                break;
            case 'Categories':
                $this->_getTaxonomy('import.categories', 'Category', 'Categoria', 'SubCategoria');
                break;
            case 'Accesses':
                $this->_getTaxonomy('import.accesses', 'Access', 'Acesso', 'SubAcesso');
                break;
            case 'Areas':
                $this->_getTaxonomy('import.areas', 'Area', 'Area', 'SubArea');
                break;
            case 'Inscriptions':
                $this->_getTaxonomy('import.inscriptions', 'InscriptionType', 'Inscricao', 'SubInscricao');
                break;
            case 'Classifications':
                $this->_getTaxonomy('import.classifications', 'Classification', 'Classificacao', 'SubClassificacao');
                break;
            case 'Places':
                $this->_getTaxonomy('import.places', 'Place', 'Localizacao', 'SubLocalizacao');
                break;
            case 'Roles':
                $this->_getTaxonomy('import.roles', 'Role', 'Funcao', 'SubFuncao');
            // no break
            case 'PropertyTypes':
                $this->_getTaxonomy('import.propertyTypes', 'PropertyType', 'Imovel', 'SubImovel');
                break;
            case 'Properties':
                $this->linkify = new Linkify([
                    'attr' => [
                        'target' => '_blank'
                    ]
                ]);
                $this->_getProperties();
                break;
            case 'Epigraphs':
                $this->linkify = new Linkify([
                    'attr' => [
                        'target' => '_blank'
                    ]
                ]);
                $this->_getEpigraphs();
                break;
            case "Clean":
                $this->_cleanData($this->typesToClean);
                break;
            case "GenerateSitemap":
                $this->_generateSitemap();
                break;
        }
    }

    private function _getProperties()
    {
        $properties = [];
        try {
            $propertiesSlug = config('import.properties');

            // Generate Promise
            $promise = [];
            $promise[$this->defaultLanguage] = $this->client->getAsync($propertiesSlug, [
                'debug' => false,
                'query' => [
                    'lang' => $this->defaultLanguage
                ]
            ]);
            // Make calls - Async
            $responses = Promise\unwrap($promise);
            // Change thecodingmachine/safe/json_decode
            $properties = json_decode($responses[$this->defaultLanguage]->getBody()->getContents())->Imoveis->Imovel;
            $properties = $this->_parsePropertyChildren($properties);
        } catch (RequestException $e) {
            Log::stack([
                'importLogStack', 'rollbar'
            ])->error('Caught an exception getting Properties ---- Import<_getProperties>');
            throw new ImportException('', 0, $e);
        }

        $propertiesParsed = [];
        $propertyIds = [];
        foreach ($properties as $index => $property) {
            $propertyIds[] = $property->Imovel_ID;
            //Num_Imovel with all the information - "LxR1106002", "LxR1106005", "LxR1106049"
            //if ($property->Num_Imovel === "LxR1107009") {
            $propertyInfo = $this->_getProperty($property, count($properties) - ($index + 1));
            if (!is_null($propertyInfo)) {
                $propertiesParsed[] = $this->_parsePropertyInfo($propertyInfo);
            }
            //}
        }

        RequestContext::set('importPropertyIds', $propertyIds);
        $this->_addProperties($propertiesParsed);
    }

    private function _getEpigraphs()
    {
        $epigraphs = [];
        try {
            $epigraphsSlug = config('import.objects');

            // Generate Promise
            $promise = [];
            $promise[$this->defaultLanguage] = $this->client->getAsync($epigraphsSlug, [
                'debug' => false,
                'query' => [
                    'lang' => $this->defaultLanguage
                ]
            ]);

            // Make calls - Async
            $responses = Promise\unwrap($promise);
            // Change thecodingmachine/safe/json_decode
            $epigraphs = json_decode($responses[$this->defaultLanguage]->getBody()->getContents())->Objecto->Objecto;
            $epigraphs = $this->_parseEpigraphChildren($epigraphs);
        } catch (RequestException $e) {
            Log::stack([
                'importLogStack', 'rollbar'
            ])->error('Caught an exception getting Epigraphs ---- Import<_getEpigraphs>');
            throw new ImportException('', 0, $e);
        }

        $epigraphsParsed = [];
        $epigraphIds = [];
        foreach ($epigraphs as $index => $epigraph) {
            $epigraphIds[] = $epigraph->Objecto_ID;
           //if ($epigraph->Num_Inventario === "LxRomana1106037") {
                /* if (count($epigraphs) - ($index + 1) === 4) { */
                $epigraphInfo = $this->_getEpigraph($epigraph, count($epigraphs) - ($index + 1));
                if (!is_null($epigraphInfo)) {
                    $epigraphsParsed[] = $this->_parseEpigraphInfo($epigraphInfo);
                }
            //}
        }

        RequestContext::set('importEpigraphIds', $epigraphIds);
        $this->_addEpigraphs($epigraphsParsed);
    }

    private function _getProperty($property, $countLeft)
    {
        try {
            $propertyInfo = $this->_fetchPropertyInfo($property, $countLeft);
            $propertyInfo = $this->_parsePropertyFetchInfo($propertyInfo);
            $propertyInfo = $this->_addLastUpdates($property, $propertyInfo);

            return $propertyInfo;
        } catch (RequestException $e) {
            Log::stack([
                'importLogStack', 'rollbar'
            ])->error('Caught an exception Fetching Properties ---- Import<_getProperty>');
            //Commented the line below so I can treat all the errors into a global var and then send them all away
            //throw new ImportException($e);
        }
    }

    private function _parsePropertyFetchInfo($propertyInfo)
    {
        foreach ($this->availableLanguages as $langCode) {
            if (isset($propertyInfo[$langCode])) {
                $propertyInfo[$langCode] = json_decode($propertyInfo[$langCode]->getBody()->getContents())->Imovel->Imovel;
                if (empty($propertyInfo[$langCode])) {
                    $importErrors = (array)RequestContext::get('importErrors');
                    $propertyId = (int)RequestContext::get('currentPropertyId');
                    $importErrors[] = "The Property with External ID ({$propertyId}) and Language ({$langCode}) is Empty.";
                    RequestContext::set('importErrors', $importErrors);
                    unset($propertyInfo[$langCode]);
                }
            }
        }

        return $propertyInfo;
    }

    private function _addLastUpdates($item, $propertyInfo)
    {
        // Let there be dragons
        foreach ($this->availableLanguages as $langCode) {
            if ($langCode === $this->defaultLanguage) {
                $propertyInfo[$langCode]->Dt_Actualizacao = $this->_getPropertyLastUpdate($item);
            } elseif (!empty($item->children) && isset($item->children[$langCode])) {
                if (isset($propertyInfo[$langCode])) {
                    $propertyInfo[$langCode]->Dt_Actualizacao = $this->_getPropertyLastUpdate($item->children[$langCode]);
                }
            }
        }

        return $propertyInfo;
    }

    private function _parsePropertyInfo($property)
    {
        // Let there be dragons
        $propertyArgs = [];
        $propertyArgs['external_id'] = $this->_getPropertyInfoApiExternalId($property);
        $propertyArgs['title'] = $this->_getPropertyInfoApiNum($property);
        //COMMENT
        $propertyArgs['images'] = $this->_getImages($property, 'ImagensGaleria', 'ID');
        $propertyArgs['videos'] = $this->_getVideos($property, 'AudioVisual', 'EnderecoWeb', 'Endereco', 'Titulo');
        $propertyArgs['objects'] = $this->_getObjects($property, 'ObjetosRelacionados', 'Objecto_ID');
        $propertyArgs['themes'] = $this->_getGenericTaxonomy($property, 'Tema', 'IDTema');
        $propertyArgs['classifications'] = $this->_getGenericTaxonomy($property, 'Classificacao', 'ClassificacaoID');
        $propertyArgs['property_type'] = $this->_getGenericTaxonomy($property, 'TipoImovel', 'IDTipoImovel');
        $propertyArgs['typologies'] = $this->_getGenericTaxonomy($property, 'Tipologia', 'TipologiaID');
        $propertyArgs['accesses'] = $this->_getGenericTaxonomy($property, 'Acesso', 'AcessoID');
        $propertyArgs['chronologies'] = $this->_getChronologies($property, 'Cronologia', 2);
        $propertyArgs['audiovisuals'] = $this->_getAudioVisuals($property);
        foreach ($this->availableLanguages as $langCode) {
            if (isset($property[$langCode])) {
                $propertyLang = $property[$langCode];
                $propertyArgs[$langCode] = [];
                $propertyArgs[$langCode]['last_update'] = $this->_getPropertyLastUpdate($propertyLang);
                $propertyArgs[$langCode]['excavation'] = $this->_getPropertyExcavationDesignation($propertyLang);
                $propertyArgs[$langCode]['location'] = $this->_getPropertyLocation($propertyLang);
                $propertyArgs[$langCode]['description'] = $this->_getMultidescriptorItem(
                    $propertyLang,
                    'Descrição editada',
                    'DescricaoHTML'
                );
                $propertyArgs[$langCode]['property_title'] = $this->_getMultidescriptorItem(
                    $propertyLang,
                    'Título',
                    'DescricaoHTML'
                );
                $propertyArgs[$langCode]['reading_suggestion'] = $this->_getMultidescriptorItem(
                    $propertyLang,
                    'Sugestão de leitura',
                    'DescricaoHTML'
                );
                $propertyArgs[$langCode]['plunder_locations'] = $this->_getMultidescriptorItem(
                    $propertyLang,
                    'Locais de espólio',
                    'DescricaoHTML'
                );
                $propertyArgs[$langCode]['popup_description'] = $this->_getMultidescriptorItem(
                    $propertyLang,
                    'Descrição "pop-up"',
                    'DescricaoHTML'
                );
            }
        }
        return $propertyArgs;
    }

    private function _getEpigraph($epigraph, $countLeft)
    {
        try {
            $epigraphInfo = $this->_fetchEpigraphInfo($epigraph, $countLeft);
            $epigraphInfo = $this->_parseObjectFetchInfo($epigraphInfo);
            $epigraphInfo = $this->_addLastUpdates($epigraph, $epigraphInfo);

            return $epigraphInfo;
        } catch (RequestException $e) {
            Log::stack([
                'importLogStack', 'rollbar'
            ])->error('Caught an exception Fetching an Epigraph ---- Import<_getEpigraph> ---->' . $e);
        }
    }

    private function _parseObjectoInfo($object)
    {
        // Let there be dragons
        $objectArgs = [];
        $objectArgs['external_id'] = $this->_getObjectInfoApiNum($object);
        $objectArgs['title'] = $this->_getObjectInfoApiNum($object);
        $objectArgs['location'] = $this->_getObjectLocation($object);
        $objectArgs['themes'] = $this->_getGenericTaxonomy($object, 'Tema', 'TemaID');
        $objectArgs['classifications'] = $this->_getGenericTaxonomy($object, 'Classificacao', 'ClassificacaoID');
        $objectArgs['videos'] = $this->_getVideos($object, 'AudioVisual', 'EnderecoWeb', 'Endereco', 'Titulo');
        $objectArgs['images'] = $this->_getImages($object, 'ImagensGaleria', 'ID');

        foreach ($this->availableLanguages as $langCode) {
            if (isset($object[$langCode])) {
                $objectLang = $object[$langCode];
                $objectArgs[$langCode] = [];
                //$objectArgs[$langCode]['last_update'] = $this->_getPropertyLastUpdate($objectLang);
                $objectArgs[$langCode]['description'] = $this->_getMultidescriptorItem(
                    $objectLang,
                    'Descrição editada',
                    'DescricaoHTML',
                    true,
                    false
                );
                $objectArgs[$langCode]['object_title'] = $this->_getMultidescriptorItem(
                    $objectLang,
                    'Título',
                    'DescricaoHTML',
                    true,
                    false
                );
                $objectArgs[$langCode]['reading_suggestion'] = $this->_getMultidescriptorItem(
                    $objectLang,
                    'Sugestão de leitura',
                    'DescricaoHTML',
                    true,
                    false
                );
                $objectArgs[$langCode]['useful_links'] = $this->_getMultidescriptorItem(
                    $objectLang,
                    'Locais de espólio',
                    'DescricaoHTML',
                    true,
                    false
                );
            }
        }

        return $objectArgs;
    }


    private function _parseEpigraphInfo($epigraph)
    {
        // Let there be dragons
        $epigraphArgs = [];
        $epigraphArgs['external_reference'] = $this->_getObjectInfoApiNum($epigraph);
        $epigraphArgs['external_id'] = $this->_getEpigraphInfoApiExternalId($epigraph);
        $epigraphArgs['relatedProperties'] = $this->_getRelatedProperties($epigraph[$this->defaultLanguage]);
        $epigraphArgs['themes'] = $this->_getGenericTaxonomy($epigraph, 'Tema', 'TemaID');
        $epigraphArgs['classifications'] = $this->_getGenericTaxonomy($epigraph, 'Classificacao', 'ClassificacaoID');
        $epigraphArgs['videos'] = $this->_getVideos($epigraph, 'AudioVisual', 'EnderecoWeb', 'Endereco', 'Titulo');
        //COMMENT
        $epigraphArgs['images'] = $this->_getImages($epigraph, 'ImagensGaleria', 'ID');
        $epigraphArgs['local_id'] = $this->_getContextField($epigraph[$this->defaultLanguage], 'LocalAdministrativoID');
        $epigraphArgs['chronologies'] = $this->_getChronologies($epigraph, 'Cronologia', 2);
        $epigraphArgs['technique'] = $this->_getInscriptionTaxonomies($epigraph, 'Inscricao', 2, 'Tecnica',
            'TecnicaID');
        $epigraphArgs['idiom'] = $this->_getInscriptionTaxonomies($epigraph, 'Inscricao', 2, 'Idioma', 'IdiomaID');
        $epigraphArgs['inscription_type'] = $this->_getInscriptionTaxonomies($epigraph, 'Inscricao', 2, 'TipoInscricao',
            'TipoInscricaoID');
        $epigraphArgs['audiovisuals'] = $this->_getAudioVisuals($epigraph);
        foreach ($this->availableLanguages as $langCode) {
            if (isset($epigraph[$langCode])) {
                $epigraphLang = $epigraph[$langCode];
                $epigraphArgs[$langCode] = [];
                $epigraphArgs[$langCode]['last_update'] = $this->_getPropertyLastUpdate($epigraphLang);
                $epigraphArgs[$langCode]['title'] = $this->_getField($epigraphLang, 'Titulo');
                $epigraphArgs[$langCode]['present_location'] = $this->_getEpigraphLocation($epigraphLang);
                $epigraphArgs[$langCode]['location_found'] = $this->_getContextField($epigraphLang, 'Morada');
                $epigraphArgs[$langCode]['inscription_text'] = $this->_getTwoLevelField($epigraphLang, 'Inscricao',
                    'Texto');
                $epigraphArgs[$langCode]['inscription_translation'] = $this->_getTwoLevelField($epigraphLang,
                    'Inscricao', 'Traducao');
                $epigraphArgs[$langCode]['description'] = $this->_getMultidescriptorItem(
                    $epigraphLang,
                    'Descrição editada',
                    'DescricaoHTML',
                    true,
                    false
                );
                $epigraphArgs[$langCode]['epigraph_title'] = $this->_getMultidescriptorItem(
                    $epigraphLang,
                    'Título',
                    'DescricaoHTML',
                    true,
                    false
                );
                $epigraphArgs[$langCode]['reading_suggestion'] = $this->_getMultidescriptorItem(
                    $epigraphLang,
                    'Sugestão de leitura',
                    'DescricaoHTML',
                    true,
                    false
                );
                $epigraphArgs[$langCode]['plunder_location'] = $this->_getMultidescriptorItem(
                    $epigraphLang,
                    'Locais de espólio',
                    'DescricaoHTML',
                    true,
                    false
                );
                /* $propertyArgs[$langCode]['popup_description'] = $this->_getMultidescriptorItem($epigraphLang,
                'Descrição "pop-up"',
                'DescricaoHTML', true, false); */
            }
        }
        return $epigraphArgs;
    }

    private function _getGenericTaxonomy($item, $taxonomyLocation, $taxonomyID)
    {
        if (!isset($item[$this->defaultLanguage])) {
            return [];
        }
        $item = $item[$this->defaultLanguage];
        $taxonomy = [];
        if (property_exists($item, $taxonomyLocation) && property_exists($item->$taxonomyLocation, $taxonomyLocation)) {
            $taxonomyInfo = $item->$taxonomyLocation->$taxonomyLocation;
            if (is_array($taxonomyInfo)) {
                foreach ($taxonomyInfo as $taxonomyInfoItem) {
                    $taxonomy[] = $taxonomyInfoItem->$taxonomyID;
                }
            } else {
                $taxonomy[] = $taxonomyInfo->$taxonomyID;
            }
        }

        return $taxonomy;
    }

    private function _getRelatedProperties($epigraph)
    {
        if (property_exists($epigraph, 'ImoveisRelacionados')
            && property_exists($epigraph->ImoveisRelacionados, 'ImoveisRelacionados')) {
            $properties = [];
            $relatedProperties = $epigraph->ImoveisRelacionados->ImoveisRelacionados;
            $ids = $this->_getRelatedPropertiesIds($relatedProperties);
            return $ids;
            //<->
        }
        return [];
    }

    private function _getRelatedPropertiesIds($properties)
    {
        $ids = [];
        if (is_array($properties)) {
            foreach ($properties as $property) {
                if (property_exists($property, 'ID')) {
                    $ids[] = $property->ID;
                }
            }
        } else {
            if (property_exists($properties, 'ID')) {
                $ids[] = $properties->ID;
            }
        }
        return $ids;
    }

    private function _getField($property, $field)
    {
        if (property_exists($property, $field)) {
            if (is_array($property->$field)) {
                return $property->$field[0];
            } else {
                return $property->$field;
            }
        } else {
            return "Unknown_" . random_string();
        }
        Log::stack(['importLogStack', 'rollbar'])->error('Property doesn\'t have ' . $field) . ' ---- Import<_getField>';
        throw new ImportException('Property must have' . $field, 0);
    }

    private function _getTwoLevelField($property, $levelField, $field)
    {
        if (property_exists($property, $levelField)) {
            if (property_exists($property->$levelField, $levelField)) {
                if (property_exists($property->$levelField->$levelField, $field)) {
                    if (is_array($property->$levelField->$levelField->$field)) {
                        return $property->$levelField->$levelField->$field[0];
                    } else {
                        return $property->$levelField->$levelField->$field;
                    }
                } else {
                    return "";
                }
            } else {
                return "";
            }
        } else {
            return "";
        }
    }

    private function _getAudioVisuals($item)
    {
        $fields = [];
        foreach ($this->availableLanguages as $keyCode => $lang) {
            if (array_key_exists($lang, $item)) {
                $currentItemLang = $item[$lang];
                if (property_exists($currentItemLang, 'AudioVisual')) {
                    if (property_exists($currentItemLang->AudioVisual, 'AudioVisual')) {
                        $currentItemLangData = $currentItemLang->AudioVisual->AudioVisual;
                        if (is_array($currentItemLangData)) {
                            foreach ($currentItemLangData as $key => $singleItemLang) {
                                $audiovisual = [];
                                if ($lang !== $this->defaultLanguage && !isset($fields[$key])) {
                                    continue;
                                }
                                if (isset($fields[$key])) {
                                    $audiovisual = $fields[$key];
                                }
                                $audiovisual[$lang] = [
                                    'title' => property_exists($singleItemLang,
                                        'Titulo') ? $singleItemLang->Titulo : "",
                                    'type' => property_exists($singleItemLang,
                                        'TipoAudiovisual') ? $singleItemLang->TipoAudiovisual : "",
                                    'external_id' => $singleItemLang->ID
                                ];
                                if (property_exists($singleItemLang, 'EnderecoWeb')) {
                                    if (property_exists($singleItemLang->EnderecoWeb, 'EnderecoWeb')) {
                                        $audiovisual[$lang]['link'] = property_exists($singleItemLang->EnderecoWeb->EnderecoWeb,
                                            'Endereco') ? $singleItemLang->EnderecoWeb->EnderecoWeb->Endereco : "";
                                    } else {
                                        $audiovisual[$lang]['link'] = "";
                                    }
                                } else {
                                    $audiovisual[$lang]['link'] = "";
                                }
                                $info = Embed::create($audiovisual[$lang]['link']);
                                $image = $info && $info->image ? $info->image : null;
                                if (!is_null($image)) {
                                    $fields[$key] = $audiovisual;
                                }
                            }
                        } else {
                            if (isset($fields[0])) {
                                $audiovisual = $fields[0];
                            }
                            $audiovisual[$lang] = [
                                'title' => property_exists($currentItemLangData,
                                    'Titulo') ? $currentItemLangData->Titulo : "",
                                'type' => property_exists($currentItemLangData,
                                    'TipoAudiovisual') ? $currentItemLangData->TipoAudiovisual : "",
                                'external_id' => $currentItemLangData->ID,
                            ];
                            if (property_exists($currentItemLangData, 'EnderecoWeb')) {
                                if (property_exists($currentItemLangData->EnderecoWeb, 'EnderecoWeb')) {
                                    $audiovisual[$lang]['link'] = property_exists($currentItemLangData->EnderecoWeb->EnderecoWeb,
                                        'Endereco') ? $currentItemLangData->EnderecoWeb->EnderecoWeb->Endereco : "";
                                } else {
                                    $audiovisual[$lang]['link'] = "";
                                }
                            } else {
                                $audiovisual[$lang]['link'] = "";
                            }
                            $info = Embed::create($audiovisual[$lang]['link']);
                            $image = $info && $info->image ? $info->image : null;
                            if (!is_null($image)) {
                                $fields = [$audiovisual];
                            }
                        }
                    }
                }
            }
        }
        return $fields;
    }

    private function _getVideos($item, $videosLocation, $videoLocation, $videoUrlLocation, $videoTitleLocation)
    {
        if (!isset($item[$this->defaultLanguage])) {
            return [];
        }
        $item = $item[$this->defaultLanguage];
        $videos = [];
        if (property_exists($item, $videosLocation) && property_exists($item->$videosLocation, $videosLocation)) {
            $videosInfo = $item->$videosLocation->$videosLocation;
            if (is_array($videosInfo)) {
                foreach ($videosInfo as $videoInfoItem) {
                    $videos[] = [
                        'title' => $videoInfoItem->$videoTitleLocation,
                        'url' => $videoInfoItem->$videoLocation->$videoLocation->$videoUrlLocation
                    ];
                }
            } else {
                $videos[] = [
                    'title' => $videosInfo->$videoTitleLocation,
                    'url' => $videosInfo->$videoLocation->$videoLocation->$videoUrlLocation
                ];
            }
        }

        return $videos;
    }

    private function _getImages($item, $imagesLocation, $imageID)
    {
        $imagesParsed = [];

        if (!isset($item[$this->defaultLanguage])) {
            return $imagesParsed;
        }

        $item = $item[$this->defaultLanguage];

        $images = [];
        if (
            property_exists($item, $imagesLocation) &&
            property_exists($item->$imagesLocation, $imagesLocation)
        ) {
            $imagesInfo = $item->$imagesLocation->$imagesLocation;
            if (is_array($imagesInfo)) {
                foreach ($imagesInfo as $imageInfoItem) {
                    $images[] = $imageInfoItem->$imageID;
                }
            } else {
                $images[] = $imagesInfo->$imageID;
            }
        }

        foreach ($images as $index => $imageID) {
            $imageInfo = $this->_getImage($imageID);
            if (!is_null($imageInfo)) {
                $imagesParsed[] = $imageInfo;
            }
        }

        return $imagesParsed;
    }

    private function _getPropertyLocation($item)
    {
        $location = [];

        if (
            property_exists($item, 'Localizacao') &&
            property_exists($item->Localizacao, 'Localizacao')
        ) {
            $itemLocation = $item->Localizacao->Localizacao;
            if (is_array($itemLocation) && count($itemLocation) > 0 && !empty($itemLocation[0])) {
                $itemLocation = $itemLocation[0];
            }
            if (!empty($itemLocation)) {
                $location['local'] = property_exists(
                    $itemLocation,
                    'LocalAdministrativoID'
                ) ? $itemLocation->LocalAdministrativoID : null;
                $location['address'] = property_exists($itemLocation, 'Morada') ? $itemLocation->Morada : null;
                $location['latitude'] = property_exists($itemLocation, 'Latitude') ? $itemLocation->Latitude : null;
                $location['longitude'] = property_exists($itemLocation, 'Longitude') ? $itemLocation->Longitude : null;
                if (is_null($location['latitude']) || is_null($location['longitude'])) {
                    Log::stack([
                        'importLogStack', 'rollbar'
                    ])->error('Property with Imovel_ID (' . $item->Imovel_ID . ') doesn\'t have correct geolocations');
                }
            } else {
                Log::stack([
                    'importLogStack', 'rollbar'
                ])->error('Property with Imovel_ID (' . $item->Imovel_ID . ') doesn\'t have a location');
            }
        }

        return $location;
    }

    private function _getObjectLocation($item)
    {
        $location = [];

        if (!isset($item[$this->defaultLanguage])) {
            return $location;
        }

        $item = $item[$this->defaultLanguage];
        if (
            property_exists($item, 'Localizacao') &&
            property_exists($item->Localizacao, 'Localizacao')
        ) {
            $itemLocation = $item->Localizacao->Localizacao;

            $location['type'] = property_exists(
                $itemLocation,
                'TipoLocaliz'
            ) ? $itemLocation->TipoLocaliz : null;
            $location['address'] = property_exists($itemLocation, 'Localizacao') ? $itemLocation->Localizacao : null;
            if (is_null($location['address'])) {
                Log::stack([
                    'importLogStack', 'rollbar'
                ])->error('Object in a property with Imovel_ID (' . $item->Imovel_ID . ') doesn\'t have an address');
            }
        }

        return $location;
    }

    private function _getEpigraphLocation($item)
    {
        $location = '';
        if (
            property_exists($item, 'Localizacao') &&
            property_exists($item->Localizacao, 'Localizacao')
        ) {
            $itemLocation = $item->Localizacao->Localizacao;

            $location = property_exists($itemLocation, 'Localizacao') ? $itemLocation->Localizacao : null;
        }

        return $location;
    }

    private function _getPropertyExcavationDesignation($property)
    {
        if (property_exists($property, 'Escavacao') && property_exists($property->Escavacao, 'Escavacao')) {
            $excavation = $property->Escavacao->Escavacao;
            if (is_array($excavation)) {
                foreach ($excavation as $item) {
                    if (property_exists($item, 'Designacao') && !is_null($item->Designacao)) {
                        return $item->Designacao;
                    }
                }
            } else {
                if (property_exists($excavation, 'Designacao') && !is_null($excavation->Designacao)) {
                    return $excavation->Designacao;
                }
            }
        }
        return "";
    }

    private function _getContextField($item, $field)
    {
        $contextField = '';
        if (
            property_exists($item, 'ContextoDeCampo') &&
            property_exists($item->ContextoDeCampo, 'ContextoDeCampo')
        ) {
            $itemContextField = $item->ContextoDeCampo->ContextoDeCampo;
            if (is_array($itemContextField)) {
                $itemContextField = $itemContextField[0];
            }
            $contextField = property_exists(
                $itemContextField,
                $field
            ) ? $itemContextField->$field : null;
        }

        return $contextField;
    }

    private function _getFoundLocal($item, $field)
    {
        $contextField = 0;
        if (
            property_exists($item, 'TipoImovel') &&
            property_exists($item->TipoImovel, 'TipoImovel')
        ) {
            $itemContextField = $item->TipoImovel->TipoImovel;
            if (is_array($itemContextField)) {
                $itemContextField = $itemContextField[0];
            }
            $contextField = property_exists(
                $itemContextField,
                $field
            ) ? $itemContextField->$field : null;
        }

        return $contextField;
    }

    private function _getPropertyLastUpdate($item)
    {
        $lastUpdate = '';
        if (property_exists($item, 'Dt_Actualizacao')) {
            $lastUpdate = $item->Dt_Actualizacao;
        }

        return $lastUpdate;
    }

    private function _getMultidescriptorItem($item, $getFrom, $infoLocation, $shouldClean = true, $isProperty = true)
    {
        $value = '';
        $multiDescriptorType = "Descritor";
        if (!$isProperty) {
            $multiDescriptorType = "tipoDescritor";
        }
        if (
            property_exists($item, 'Multidescritor') &&
            property_exists($item->Multidescritor, 'Multidescritor')
        ) {
            $multiDescriptorInfo = $item->Multidescritor->Multidescritor;
            $multiDescriptor = [];
            if (!is_array($multiDescriptorInfo)) {
                $multiDescriptor[] = $multiDescriptorInfo;
            } else {
                $multiDescriptor = $multiDescriptorInfo;
            }
            foreach ($multiDescriptor as $multiDescriptorItem) {
                if (
                    property_exists($multiDescriptorItem, $multiDescriptorType) &&
                    property_exists($multiDescriptorItem, $infoLocation) &&
                    $multiDescriptorItem->$multiDescriptorType === $getFrom
                ) {
                    $value = $multiDescriptorItem->{$infoLocation};
                    if ($shouldClean) {
                        $value = strip_tags($value, $this->allowedTagsWithSup);
                        $sanitizer = new Sanitizer([$value], $this->filters, $this->customFilters);
                        $value = $sanitizer->sanitize();
                        $value = $this->linkify->process($value[0]);

                        return $value;
                    }

                    return $value;
                }
            }
        }

        return $value;
    }

    private function _getObjects($item, $objectsLocation, $objectID)
    {
        $objectsParsed = [];

        if (!isset($item[$this->defaultLanguage])) {
            return $objectsParsed;
        }

        $item = $item[$this->defaultLanguage];

        $objects = [];
        if (
            property_exists($item, $objectsLocation) &&
            property_exists($item->$objectsLocation, $objectsLocation)
        ) {
            $objectsInfo = $item->$objectsLocation->$objectsLocation;
            if (is_array($objectsInfo)) {
                foreach ($objectsInfo as $objectInfoItem) {
                    $object = $this->_parseObjectChildren($objectInfoItem);
                    $objects[] = $object;
                }
            } else {
                $object = $this->_parseObjectChildren($objectsInfo);
                $objects[] = $object;
            }
        }

        foreach ($objects as $index => $object) {
            $objectInfo = $this->_getObject($object, $objectID);
            if (!is_null($objectInfo)) {
                $objectsParsed[] = $this->_parseObjectoInfo($objectInfo);
            }
        }

        return $objectsParsed;
    }

    private function _parsePropertyChildren($properties)
    {
        foreach ($properties as $index => $property) {
            $properties[$index]->children = [];
            if (property_exists($property, 'Traducao')) {
                $propertyTranslations = $properties[$index]->Traducao->Traducao;

                // Clean children to work on it later
                $children = [];
                if (is_array($propertyTranslations)) {
                    array_walk($propertyTranslations, function ($item) use (&$children) {
                        if (property_exists($item, 'ta_IdiomaThesaurus')) {
                            $langWithoutParse = $item->ta_IdiomaThesaurus;
                            if (isset($this->parseLanguages[$langWithoutParse])) {
                                $item->ta_IdiomaThesaurus = $this->parseLanguages[$langWithoutParse];
                                $children[$item->ta_IdiomaThesaurus] = $item;
                            }
                        }
                    });
                } else {
                    if (property_exists($propertyTranslations, 'ta_IdiomaThesaurus')) {
                        $langWithoutParse = $propertyTranslations->ta_IdiomaThesaurus;
                        if (isset($this->parseLanguages[$langWithoutParse])) {
                            $propertyTranslations->ta_IdiomaThesaurus = $this->parseLanguages[$langWithoutParse];
                            $children[$propertyTranslations->ta_IdiomaThesaurus] = $propertyTranslations;
                        }
                    }
                }
                $properties[$index]->children = $children;
                unset($properties[$index]->Traducao);
            }
        }
        return $properties;
    }


    private function _parseEpigraphChildren($epigraphs)
    {
        foreach ($epigraphs as $index => $epigraph) {
            $epigraphs[$index]->children = [];
            if (property_exists($epigraph, 'Traducao')) {
                $epigraphTranslations = $epigraphs[$index]->Traducao->Traducao;
                // Clean children to work on it later
                $children = [];
                if (is_array($epigraphTranslations)) {
                    array_walk($epigraphTranslations, function ($item) use (&$children) {
                        if (property_exists($item, 'ta_IdiomaThesaurus')) {
                            $langWithoutParse = $item->ta_IdiomaThesaurus;
                            if (isset($this->parseLanguages[$langWithoutParse])) {
                                $item->ta_IdiomaThesaurus = $this->parseLanguages[$langWithoutParse];
                                $children[$item->ta_IdiomaThesaurus] = $item;
                            }
                        }
                    });
                } else {
                    if (property_exists($epigraphTranslations, 'ta_IdiomaThesaurus')) {
                        $langWithoutParse = $epigraphTranslations->ta_IdiomaThesaurus;
                        if (isset($this->parseLanguages[$langWithoutParse])) {
                            $epigraphTranslations->ta_IdiomaThesaurus = $this->parseLanguages[$langWithoutParse];
                            $children[$epigraphTranslations->ta_IdiomaThesaurus] = $epigraphTranslations;
                        }
                    }
                }
                $epigraphs[$index]->children = $children;
                unset($epigraphs[$index]->Traducao);
            }
        }

        return $epigraphs;
    }

    private function _parseObjectChildren($object)
    {
        $object->children = [];
        if (
            property_exists($object, 'idioma') &&
            property_exists($object->idioma, 'idioma')
        ) {
            $propertyTranslations = $object->idioma->idioma;

            // Clean children to work on it later
            $children = [];
            array_walk($propertyTranslations, function ($item) use (&$children) {
                if (property_exists($item, 'ta_IdiomaThesaurus')) {
                    $langWithoutParse = $item->ta_IdiomaThesaurus;
                    if (isset($this->parseLanguages[$langWithoutParse])) {
                        $item->ta_IdiomaThesaurus = $this->parseLanguages[$langWithoutParse];
                        $children[$item->ta_IdiomaThesaurus] = $item;
                    }
                }
            });
            $object->children = $children;
            unset($object->idioma);
        }

        return $object;
    }

    private function _getObject($object, $objectID)
    {
        try {
            $objectInfo = $this->_fetchObjectInfo($object, $objectID);
            $objectInfo = $this->_parseObjectFetchInfo($objectInfo);

            return $objectInfo;
        } catch (RequestException $e) {
            return null;
            // Log here
            // throw new ImportException($e);
        }
    }

    private function _getImage($imageID)
    {
        try {
            $imageInfo = $this->_fetchImageInfo($imageID);
            $imageInfo = $this->_parseImageFetchInfo($imageInfo);

            return $imageInfo;
        } catch (RequestException $e) {
            Log::stack([
                'importLogStack', 'rollbar'
            ])->error('Caught Exception trying to get Image ID (' . $imageID . ') ---- Import<_getImage>');
            throw new ImportException($e);
        }
    }

    private function _fetchImageInfo($imageID)
    {
        $imagesSlug = config('import.images');
        // Generate Promises
        $promises = [];

        foreach ($this->availableLanguages as $langCode) {
            $imagesSlug = config('import.images');
            // Generate Promises
            $promises[$langCode] = $this->client->getAsync($imagesSlug, [
                'debug' => false,
                'query' => [
                    'IDImagem' => $imageID,
                    'lang' => $langCode
                ]
            ]);
        }

        // Make calls - Async
        $responses = Promise\unwrap($promises);

        return $responses;
    }

    private function _parseImageFetchInfo($imageInfo)
    {
        $image = [];
        foreach ($this->availableLanguages as $langCode) {
            $content = (object)json_decode($imageInfo[$langCode]->getBody()->getContents());
            if (property_exists($content, 'Ficheiro')) {
                if ($langCode === $this->defaultLanguage) {
                    $imageInfoItem = $content->Ficheiro->Ficheiro;
                    $image["file"] = $imageInfoItem->Picture;
                    $image["id"] = $imageInfoItem->Ficheiro_ID;
                    $image[$langCode]["legend"] = $imageInfoItem->Legenda;
                } else {
                    $imageInfoItem = $content->Ficheiro->Ficheiro;
                    $image[$langCode]["legend"] = $imageInfoItem->Legenda;
                }
            }
        }

        return $image;
    }

    private function _parseObjectFetchInfo($objectInfo)
    {
        foreach ($this->availableLanguages as $langCode) {
            if (isset($objectInfo[$langCode])) {
                $objectInfo[$langCode] = json_decode($objectInfo[$langCode]->getBody()->getContents())->Objecto->Objecto;
                if (empty($objectInfo[$langCode])) {
                    $importErrors = (array)RequestContext::get('importErrors');
                    $objectId = (int)RequestContext::get('currentObjectId');
                    $importErrors[] = "The Object with External ID ({$objectId}) and Language ({$langCode}) is Empty.";
                    RequestContext::set('importErrors', $importErrors);
                    unset($objectInfo[$langCode]);
                }
            }
        }

        return $objectInfo;
    }

    private function _fetchObjectInfo($object, $objectID)
    {
        $objectsSlug = config('import.objects');
        // Generate Promises
        $promises = [];

        foreach ($this->availableLanguages as $langCode) {
            if ($langCode === $this->defaultLanguage) {
                $promises[$langCode] = $this->client->getAsync($objectsSlug, [
                    'debug' => false,
                    'query' => [
                        'lang' => $langCode,
                        'idobjecto' => $object->$objectID,
                        'ta_museu' => 'LxRomana'
                    ]
                ]);
            } elseif (!empty($object->children) && isset($object->children[$langCode])) {
                $promises[$langCode] = $this->client->getAsync($objectsSlug, [
                    'debug' => false,
                    'query' => [
                        'lang' => $langCode,
                        'idobjecto' => $object->children[$langCode]->$objectID,
                        'ta_museu' => 'LxRomana'
                    ]
                ]);
            }
        }

        // Make calls - Async
        $responses = Promise\unwrap($promises);

        return $responses;
    }

    private function _fetchPropertyInfo($property, $countLeft)
    {
        $propertiesSlug = config('import.properties');
        // Generate Promises
        $promises = [];
        $imovelId = 0;
        foreach ($this->availableLanguages as $langCode) {
            if ($langCode === $this->defaultLanguage) {
                $imovelId = $property->Imovel_ID;
                RequestContext::set('currentPropertyId', $imovelId);
                $promises[$langCode] = $this->client->getAsync($propertiesSlug, [
                    'debug' => false,
                    'query' => [
                        'lang' => $langCode,
                        'idimovel' => $property->Imovel_ID,
                        'ta_museu' => 'LxRomana'
                    ]
                ]);
                $promises[$langCode]->lastUpdate = $this->_getPropertyLastUpdate($property);
            } elseif (!empty($property->children) && isset($property->children[$langCode])) {
                $imovelId = $property->children[$langCode]->Imovel_ID;
                RequestContext::set('currentPropertyId', $imovelId);
                $promises[$langCode] = $this->client->getAsync($propertiesSlug, [
                    'debug' => false,
                    'query' => [
                        'lang' => $langCode,
                        'idimovel' => $property->children[$langCode]->Imovel_ID,
                        'ta_museu' => 'LxRomana'
                    ]
                ]);
                $promises[$langCode]->lastUpdate = $this->_getPropertyLastUpdate($property->children[$langCode]);
            }
        }

        // Make calls - Async
        Log::channel('importLogStack')->info('Preparing Property Data with Object ID (' . $imovelId . ') ----- ' . $countLeft . ' Left!');
        $responses = Promise\unwrap($promises);
        return $responses;
    }

    private function _fetchEpigraphInfo($epigraph, $countLeft)
    {
        $epigraphsSlug = config('import.objects');
        // Generate Promises
        $promises = [];
        $objectoId = 0;
        foreach ($this->availableLanguages as $langCode) {
            if ($langCode === $this->defaultLanguage) {
                $objectoId = $epigraph->Objecto_ID;
                RequestContext::set('currentObjectId', $objectoId);
                $promises[$langCode] = $this->client->getAsync($epigraphsSlug, [
                    'debug' => false,
                    'query' => [
                        'lang' => $langCode,
                        'idObjecto' => $epigraph->Objecto_ID,
                        'ta_museu' => 'LxRomana'
                    ]
                ]);
                $promises[$langCode]->lastUpdate = $this->_getPropertyLastUpdate($epigraph);
            } elseif (!empty($epigraph->children) && isset($epigraph->children[$langCode])) {
                $objectoId = $epigraph->children[$langCode]->Objecto_ID;
                RequestContext::set('currentObjectId', $objectoId);
                $promises[$langCode] = $this->client->getAsync($epigraphsSlug, [
                    'debug' => false,
                    'query' => [
                        'lang' => $langCode,
                        'idObjecto' => $epigraph->children[$langCode]->Objecto_ID,
                        'ta_museu' => 'LxRomana'
                    ]
                ]);
                $promises[$langCode]->lastUpdate = $this->_getPropertyLastUpdate($epigraph->children[$langCode]);
                $promises[$langCode]->externalId = $this->_getPropertyLastUpdate($epigraph->children[$langCode]->Objecto_ID);
            }
        }
        // Make calls - Async
        Log::channel('importLogStack')->info('Preparing Epigraph Data with Object ID (' . $objectoId . ') ----- ' . $countLeft . ' Left!');
        $responses = Promise\unwrap($promises);

        return $responses;
    }

    private function _getPropertyInfoApiNum($property)
    {
        if (isset($property[$this->defaultLanguage]) && property_exists(
                $property[$this->defaultLanguage],
                'Num_Imovel'
            )) {
            return $property[$this->defaultLanguage]->Num_Imovel;
        }
        Log::stack([
            'importLogStack', 'rollbar'
        ])->error('There\'s a property without Num_Imovel but we can\t say which');
        throw new ImportException('Property must have Num_Imovel', 0);
    }

    private function _getPropertyInfoApiExternalId($property)
    {
        if (isset($property[$this->defaultLanguage]) && property_exists(
                $property[$this->defaultLanguage],
                'Imovel_ID'
            )) {
            return $property[$this->defaultLanguage]->Imovel_ID;
        }
        Log::stack([
            'importLogStack', 'rollbar'
        ])->error('There\'s a property without Imovel_ID but we can\t say which');
        throw new ImportException('Property must have Imovel_ID', 0);
    }

    private function _getEpigraphInfoApiExternalId($epigraph)
    {
        if (isset($epigraph[$this->defaultLanguage]) && property_exists(
                $epigraph[$this->defaultLanguage],
                'Objecto_ID'
            )) {
            return $epigraph[$this->defaultLanguage]->Objecto_ID;
        }
        throw new ImportException('Property must have Objecto_ID', 0);
    }

    private function _getObjectInfoApiNum($object)
    {
        if (isset($object[$this->defaultLanguage]) && property_exists(
                $object[$this->defaultLanguage],
                'Num_Inventario'
            )) {
            return $object[$this->defaultLanguage]->Num_Inventario;
        }

        throw new ImportException('Object must have Num_Inventario', 0);
    }

    // Below this point:
    // _get Methods, will fetch and work the data coming from the external API
    // _add Methods, will call the importService with the data we worked.
    // For taxonomies the code is mostly repeated, but this is because of the bad api we consuming
    // Since there might be several exceptions, it's divided by taxonomy type.
    // When the api becomes more stable, we can reduce this to a single _get and _add method.

    private function _getTaxonomy(
        string $configLocation,
        string $contentType,
        string $parentLocation,
        string $childLocation
    )
    {
        try {
            $apiUrl = config($configLocation);
            // Generate Promises
            $promises = [];
            foreach ($this->availableLanguages as $langCode) {
                $promises[$langCode] = $this->client->getAsync($apiUrl, [
                    'debug' => false,
                    'query' => [
                        'lang' => $langCode
                    ]
                ]);
            }

            // Make calls - Async
            $responses = Promise\unwrap($promises);

            // Get all the content from response
            $items = [];
            foreach ($this->availableLanguages as $langCode) {
                $items[$langCode] = json_decode($responses[$langCode]->getBody()->getContents())->$parentLocation->$parentLocation;

                if (!is_array($items[$langCode])) {
                    $items[$langCode] = [$items[$langCode]];
                }

                foreach ($items[$langCode] as $index => $item) {
                    if (property_exists($item, $childLocation)) {
                        $items[$langCode][$index]->children = is_array($item->$childLocation) ? $item->$childLocation : [$item->$childLocation];
                        unset($items[$langCode][$index]->$childLocation);
                    }
                }
            }
            $this->_addTaxonomy($items, $contentType);
        } catch (RequestException $e) {
            throw new ImportException($e);
        }
    }

    private function _addTaxonomy(array $items, string $ContentType)
    {
        DB::beginTransaction();
        try {
            // Try to create the taxonomy
            ImportService::createTaxonomy($items, $ContentType);
            // Commit everything to the DB
            DB::commit();
        } catch (Throwable $e) {
            DB::rollback();
            throw new ImportException($e);
        }
    }

    private function _addProperties(array $items)
    {
        DB::beginTransaction();
        try {
            // Try to create the taxonomy
            ImportService::createProperties($items);
            // Commit everything to the DB
            DB::commit();
            $this->addSearchableAddressContent();
        } catch (Throwable $e) {
            DB::rollback();
            throw new ImportException($e);
        }
    }

    private function _addEpigraphs(array $items)
    {
        DB::beginTransaction();
        try {
            // Try to create the taxonomy
            ImportService::createEpigraphs($items);
            // Commit everything to the DB
            DB::commit();
        } catch (Throwable $e) {
            DB::rollback();
            throw new ImportException($e);
        }
    }

    private function _cleanData($types)
    {
        DB::beginTransaction();
        try {
            CleanImportService::showerData($types);
            DB::commit();
        } catch (Throwable $e) {
            DB::rollback();
            throw new ImportException($e);
        }
    }

    private function _getInscriptionInfo($epigraph)
    {
        $inscription = [];
        if (property_exists($epigraph, 'Inscricao') && property_exists($epigraph->Inscricao, 'Inscricao')) {
            $inscriptionInfo = $epigraph->Inscricao->Inscricao;
            $inscriptionTypeId = $inscriptionInfo->TipoInscricaoID !== "0" ? $inscriptionInfo->TipoInscricaoID : null;
            $inscriptionType = $inscriptionInfo->TipoInscricao;
            $techniqueId = $inscriptionInfo->TecnicaID !== "0" ? $inscriptionInfo->TecnicaID : null;
            $technique = $inscriptionInfo->Tecnica;
            $idiomId = $inscriptionInfo->IdiomaID !== "0" ? $inscriptionInfo->IdiomaID : null;
            $idiom = $inscriptionInfo->Idioma;
            $text = $inscriptionInfo->Texto;
            $translation = $inscriptionInfo->Traducao;
            if ($inscriptionTypeId) {
                $inscription['type'] = [
                    'ID' => $inscriptionTypeId,
                    'value' => $inscriptionType
                ];
            }
            if ($techniqueId) {
                $inscription['technique'] = [
                    'ID' => $techniqueId,
                    'value' => $technique
                ];
            }
            if ($idiomId) {
                $inscription['idiom'] = [
                    'ID' => $idiomId,
                    'value' => $idiom
                ];
            }
            $inscription['text'] = $text;
            $inscription['translation'] = $translation;
            return $inscription;
        }
        return null;
    }

    private function _getChronologies($item, string $levelField, int $levelCount)
    {
        $fields = [];
        $isArray = false;
        foreach ($this->availableLanguages as $lang) {
            if (array_key_exists($lang, $item)) {
                $itemLang = $item[$lang];
                for ($i = 1; $i <= $levelCount; $i++) {
                    if (property_exists($itemLang, $levelField)) {
                        $itemLang = $itemLang->$levelField;
                    } else {
                        return null;
                    }
                }
                if (is_array($itemLang)) {
                    $isArray = true;
                    foreach ($itemLang as $key => $singleItemLang) {
                        if ($lang !== $this->defaultLanguage && !isset($fields[$key])) {
                            continue;
                        }
                        if (isset($fields[$key])) {
                            $chronology = $fields[$key];
                        }
                        $chronology[$lang] = [
                            'date_start' => (int)filter_var($singleItemLang->DataInicial, FILTER_SANITIZE_NUMBER_INT),
                            'date_end' => (int)filter_var($singleItemLang->DataFinal, FILTER_SANITIZE_NUMBER_INT),
                            'title' => $singleItemLang->DataTextual,
                            'descriptive_text' => $singleItemLang->ParteDescritiva,
                        ];
                        if ($lang === $this->defaultLanguage) {
                            $chronology[$lang]['external_id'] = $singleItemLang->ID;
                        }
                        $fields[$key] = $chronology;
                    }
                } else {
                    if (isset($fields[0])) {
                        $chronology = $fields[0];
                    }
                    $chronology[$lang] = [
                        'date_start' => (int)filter_var($itemLang->DataInicial, FILTER_SANITIZE_NUMBER_INT),
                        'date_end' => (int)filter_var($itemLang->DataFinal, FILTER_SANITIZE_NUMBER_INT),
                        'title' => $itemLang->DataTextual,
                        'descriptive_text' => $itemLang->ParteDescritiva,
                    ];
                    if ($lang === $this->defaultLanguage) {
                        $chronology[$lang]['external_id'] = $itemLang->ID;
                    }
                    $fields = [$chronology];
                }
            }
        }
        return $fields;
    }

    private function _getInscriptionTaxonomies(
        $item,
        string $levelField,
        int $levelCount,
        string $field,
        string $idField
    )
    {
        $fields = [];
        foreach ($this->availableLanguages as $lang) {
            if (array_key_exists($lang, $item)) {
                $itemLang = $item[$lang];
                for ($i = 1; $i <= $levelCount; $i++) {
                    if (property_exists($itemLang, $levelField)) {
                        $itemLang = $itemLang->$levelField;
                    } else {
                        return null;
                    }
                }
                if (property_exists($itemLang, $field)) {
                    $treatedField = $field;
                    $treatedField[strlen($field) - 1] = strtolower($field[strlen($field) - 1]);
                    $fields[$lang][Str::snake($treatedField)] = $itemLang->$field;
                } else {
                    return null;
                }
                if ($lang === $this->defaultLanguage) {
                    if (property_exists($itemLang, $idField)) {
                        $treatedField = $idField;
                        $treatedField[strlen($idField) - 1] = strtolower($idField[strlen($idField) - 1]);
                        $fields[$lang][Str::snake($treatedField)] = $itemLang->$idField;
                    } else {
                        return null;
                    }
                }
            }
        }
        return $fields;
    }

    private function addSearchableAddressContent()
    {
        foreach ($this->availableLanguages as $lang) {
            DB::statement("UPDATE property_languages inner join properties on property_languages.property_id = properties.id inner join location_languages on location_languages.location_id = properties.local_id and location_languages.language_id = '" . $lang . "' SET searchable_address = CONCAT(address, ', ', location_languages.title) WHERE property_languages.language_id = '" . $lang . "'");
        }
    }

    private function _generateSitemap()
    {
        DB::beginTransaction();
        try {
            ImportService::generateSitemap();
            DB::commit();
        } catch (Throwable $e) {
            DB::rollback();
            throw new ImportException($e);
        }
    }
}
