<?php
namespace App\Services;

use App\Facades\Backoffice\ContentTypes;
use App\Jobs\Backoffice\ProcessSearch;
use App\Libs\Backoffice\Managers\MediaManager;
use App\Models\Backoffice\MediaFolder;
use App\Models\Backoffice\MediaItem;
use App\Models\Backoffice\WebsiteObject;
use App\Models\Backoffice\WebsiteObjectLanguage;
use App\Models\BuildingType;
use App\Models\Competition;
use App\Models\CompetitionLanguage;
use App\Models\Country;
use App\Models\Cpv;
use App\Models\Nuts3Region;
use App\Models\ProcedureType;
use App\Models\Result;
use App\Models\ResultDate;
use App\Models\ResultDateLanguage;
use App\Models\ResultEntity;
use App\Models\ResultEntityLanguage;
use App\Models\ResultLanguage;
use App\Models\ResultWinner;
use App\Models\ResultWinnerLanguage;
use App\Models\TrackedResult;
use App\Models\TrackedResultLanguage;
use Carbon\Carbon;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
use Illuminate\Support\Str;
use Throwable;

class PimcoreImportService
{
    /**
     * The database connection for Pimcore.
     *
     * @var \Illuminate\Database\Connection
     */
    protected $connection;
    protected $mediaManager;
    protected $competitionsFolder;
    protected $procedureTypeMap = [];
    protected $competitionBaseUri = [];
    protected $resultBaseUri = [];
    protected $trackedResultBaseUri = [];
    protected $pimcoreAdminSid;
    protected $buildingTypesMapping = [];

    /**
     * Create a new PimcoreImportService instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->connection = DB::connection('pimcore');

        $sourceProcedureTypes = $this->connection->table('object_query_6')->get();
        $procedureTypes = ProcedureType::get()->keyBy('migration_type_id');
        $this->procedureTypeMap = [];
        foreach ($sourceProcedureTypes as $sourceProcedureType) {
            $procedureType = $procedureTypes->get($sourceProcedureType->typeId);
            if ($procedureType) {
                $this->procedureTypeMap[$sourceProcedureType->oo_id] = $procedureType;
            }
        }


        $competitionConfig = config('backoffice.contentTypes.competition');
        $this->competitionBaseUri = $competitionConfig['baseUri'];

        $resultConfig = config('backoffice.contentTypes.result');
        $this->resultBaseUri = $resultConfig['baseUri'];

        $trackedResultConfig = config('backoffice.contentTypes.tracked_result');
        $this->trackedResultBaseUri = $trackedResultConfig['baseUri'];

        $this->buildingTypesMapping = $this->getBuildingTypeMapping();

        $this->mediaManager = new MediaManager();
        $rootFolder = $this->mediaManager->getFolder();
        $this->competitionsFolder = MediaFolder::where('base_folder', 'media')
            ->where('name', 'competitions')
            ->where('parent_id', $rootFolder->id)
            ->first();
        if (!$this->competitionsFolder) {
            $this->competitionsFolder = $this->mediaManager->createFolder('competitions', $rootFolder->id);
        }
    }

    /**
     * Import competitions from Pimcore along with their results and tracked results.
     *
     * @return void
     */
    public function importCompetitions(int $fromId, int $toId, string $pimcoreAdminSid, bool $resultsOnly = false)
    {
        $this->pimcoreAdminSid = $pimcoreAdminSid;

        if ($resultsOnly) {
            Log::info('Importing results and tracked results for competitions with IDs between ' . $fromId . ' and ' . $toId);
            $tenders = $this->connection
                ->table('object_brick_query_Ergebnis_3')
                ->whereBetween('o_id', [$fromId, $toId])
                ->orderBy('o_id', 'asc')
                ->get();
        } else {
            Log::info('Importing competitions with IDs between ' . $fromId . ' and ' . $toId);
            $tenders = $this->connection
                ->table('object_query_3')
                ->whereBetween('oo_id', [$fromId, $toId])
                ->orderBy('oo_id', 'asc')
                ->get();
        }


        Log::info('Found ' . count($tenders) . ' competitions to import from Pimcore with IDs between ' . $fromId . ' and ' . $toId);
        foreach ($tenders as $tender) {
            $importId = $resultsOnly ? $tender->o_id : $tender->oo_id;
            $competition = $this->importCompetition($importId);
            // $competition = Competition::where('wa_id', '2039775')->first();
            if (!$competition) {
                Log::warning('Competition does not exist and could not import from Pimcore (O_ID): ' . $importId);
                continue;
            }

            if ($competition->result == null) {
                $this->importResult($importId, $competition);
            } else {
                Log::info('Competition ' . $competition->wa_id . ' already has result, skipping...');
            }

            if ($competition->trackedResult == null) {
                $this->importTrackedResult($importId, $competition);
            } else {
                Log::info('Competition ' . $competition->wa_id . ' already has tracked result, skipping...');
            }
        }
        return;
    }

    /**
     * Import an asset from Pimcore.
     *
     * @param integer $pimcoreAssetId
     * @return MediaItem|null
     */
    public function importAsset(int $pimcoreAssetId, $folder = ''): ?MediaItem
    {
        $mediaItem =  MediaItem::where('pimcore_id', $pimcoreAssetId)->first();
        if ($mediaItem) {
            Log::info('Asset already exists in MediaItems: ' . $pimcoreAssetId);
            return $mediaItem;
        }
        $asset = $this->connection->table('assets')->where('id', $pimcoreAssetId)->first();
        $assetMetadata = $this->connection->table('assets_metadata')->where('cid', $pimcoreAssetId)->get()->keyBy('name');

        if (!$asset) {
            Log::warning('Asset not found for ID ' . $pimcoreAssetId);
            return null;
        }
        $filename = $asset->filename;
        $extension = pathinfo($filename, PATHINFO_EXTENSION);
        $targetFilename = Str::random(32) . ".$extension";
        $settings = [];

        if ($asset->customSettings) {
            $settings = unserialize($asset->customSettings);
        }

        if (
            !in_array($extension, config('backoffice.media.allowedExts.image')) &&
            !in_array($extension, config('backoffice.media.allowedExts.document'))
        ) {
            Log::warning('File type (' . $extension . ') not allowed for ID ' . $pimcoreAssetId);
            return null;
        }

        $path = $asset->path;

        $client = new Client();

        // Add the cookie to the request
        $response = $client->get("https://www.wettbewerbe-aktuell.de/admin/asset/download/id/$pimcoreAssetId", [
            'allow_redirects' => false,
            'headers' => [
                'Cookie' => "pimcore_admin_sid=$this->pimcoreAdminSid",
            ],
        ]);

        if ($response->getStatusCode() !== 200) {
            Log::error('Failed to download asset with ID ' . $pimcoreAssetId . ': ' . $response->getReasonPhrase());
            throw new \Exception('Failed to download asset with ID ' . $pimcoreAssetId . ': ' . $response->getReasonPhrase());
        }
        $body = $response->getBody();

        if ($folder) {
            $targetFolder = MediaFolder::where('base_folder', 'media')
                ->where('parent_id', $this->competitionsFolder->id)
                ->where('name', $folder)
                ->first();

            if (!$targetFolder) {
                $targetFolder = $this->mediaManager->createFolder($folder, $this->competitionsFolder->id);
            }
        } else {
            $targetFolder = $this->competitionsFolder;
        }

        Storage::disk('media')->put($targetFolder->path . '/' . $targetFilename, $body->getContents());

        $item = new MediaItem();

        $item->filename = $targetFilename;
        $item->extension = $extension;
        $item->original_filename = $filename;
        $item->related_type = 'result';
        $item->media_type = 'image';
        $item->base_folder = 'media';
        $item->path = trim($targetFolder->path, '/') . '/' . $targetFilename;
        $item->media_folder_id = $targetFolder->id;

        if ($assetMetadata->has('title')) {
            $item->title = mb_substr($assetMetadata->get('title')->data, 0, 500);
        } else {
            $item->title = $filename;
        }
        $item->alt = $item->title;
        if (isset($settings['imageWidth']) && isset($settings['imageHeight'])) {
            $item->width = $settings['imageWidth'];
            $item->height = $settings['imageHeight'];
        }
        $item->size = $body->getSize();
        $item->backend_user_id = 1;
        $item->pimcore_id = $pimcoreAssetId;

        $item->save();
        return $item;
    }

    /**
     * Import a competition from Pimcore.
     *
     * @param integer $competitionObjectId
     * @return Competition|null
     */
    public function importCompetition(int $competitionObjectId): ?Competition
    {
        $source = $this->connection->table('object_query_3')
            ->where('oo_id', $competitionObjectId)
            ->whereNull('TestObject')
            ->first();

        if (!$source) {
            Log::warning('Competition not found for ID ' . $competitionObjectId);
            return null;
        }

        $sourceExtra = $this->connection->table('object_brick_query_Ausschreibung_3')->where('o_id', $competitionObjectId)->first();
        $sourceExtraStore = $this->connection->table('object_brick_store_Ausschreibung_3')->where('o_id', $competitionObjectId)->first();
        $sourceObject = $this->connection->table('objects')->where('o_id', $competitionObjectId)->first();

        $waId = $sourceObject->o_key;

        $competition = Competition::where('wa_id', $waId)->first();
        if ($competition) {
            Log::info("Competition with WA ID $waId already exists, skipping import.");
            return $competition;
        }

        DB::beginTransaction();
        try {
            $competition = new Competition();

            //$competition->xml_url = '';
            //$competition->html_url = $htmlUrl;
            $competition->wa_id = $waId;
            $competition->meta_title = $source->seoTitle ? mb_substr($source->seoTitle, 0, 255) : mb_substr($source->title, 0, 255);
            $competition->promoter = $source->auslober ? mb_substr($source->auslober, 0, 100) : null;
            $competition->is_competition = $source->isCompetition ?? true;
            $competition->is_public = $source->isCompetition ?? true;

            //$competition->promoter_address = $organizationAddress;
            //$competition->promoter_postal_code = $organizationZip;
            //$competition->promoter_city = $organizationCity;
            //$competition->promoter_nuts_code = $organizationNutsCode;
            //$competition->promoterCountry()->associate($promoterCountry);
            //$competition->contact_name = $contactName;
            //$competition->contact_phone = $contactPhone;
            //$competition->contact_email = $contactEmail;

            $procedureType = key_exists($source->announcementType__id, $this->procedureTypeMap)
                ? $this->procedureTypeMap[$source->announcementType__id]
                : null;
            if (!$procedureType) {
                Log::warning('Procedure type not found for ID ' . $source->announcementType__id);
            }
            $competition->procedure_type_text = $source->announcementTypeText;

            $competition->location_address = $source->streetNo ? mb_substr($source->streetNo, 0, 255) : null;
            $competition->location_postal_code = $source->zip ? mb_substr($source->zip, 0, 50) : null;
            $competition->location_city = $source->city ? mb_substr($source->city, 0, 255) : null;
            if ($source->country) {
                $locationCountry = Country::where('iso2', $source->country)->first();
                if (!$locationCountry) {
                    Log::warning("Country not found for code " . $source->country);
                } else {
                    $competition->locationCountry()->associate($locationCountry);
                }
            }
            $competition->participant = $source->teilnehmergruppe;

            if ($source->nutsCodes) {
                $sourceNutsCodes = explode(',', $source->nutsCodes);
                $nutsCodeObjectId = intval(substr($sourceNutsCodes[1], 7));
                $nutsCodeObject = $this->connection->table('object_query_42')->where('oo_id', $nutsCodeObjectId)->first();
                if ($nutsCodeObject) {
                    $locationNutsCode = $nutsCodeObject->NutsCode;
                    $locationNutsRegion = Nuts3Region::where('code', $locationNutsCode)->first();
                    $competition->location_nuts_code = $locationNutsCode;
                    if ($locationNutsRegion) {
                        $competition->nuts3Region()->associate($locationNutsRegion);
                    } else {
                        Log::warning('Nuts region not found for code ' . $locationNutsCode);
                    }
                } else {
                    Log::warning('Nuts code object not found for ID ' . $nutsCodeObjectId);
                }
            } else {
                // Try to find NUTS code from postal code lookup
                if ($source->country && $source->zip) {
                    $postalCode = preg_replace('/\s+/', '', $source->zip);
                    $nuts3PostalCode = DB::table('nuts3_postal_codes')
                        ->where('country_code', $source->country)
                        ->where('postal_code', $postalCode)
                        ->first();

                    if ($nuts3PostalCode) {
                        $locationNutsCode = $nuts3PostalCode->nuts3_code;
                        $locationNutsRegion = Nuts3Region::where('code', $locationNutsCode)->first();
                        $competition->location_nuts_code = $locationNutsCode;
                        if ($locationNutsRegion) {
                            $competition->nuts3Region()->associate($locationNutsRegion);
                        } else {
                            Log::warning('Nuts region not found for code ' . $locationNutsCode);
                        }
                    } else {
                        Log::warning('No NUTS code found for competition with ID ' . $competitionObjectId . ' (country: ' . $source->country . ', postal code: ' . $source->zip . ')');
                    }
                } else {
                    Log::warning('No NUTS code provided for competition with ID ' . $competitionObjectId);
                }
            }

            if ($sourceExtra) {
                $competition->coordination = $sourceExtra->announcementCoordination;
                $competition->original_language_code = $sourceExtra->announcementOriginalLanguage;
                $competition->publication_date = Carbon::createFromTimestamp($sourceExtra->announcementDate);

                if ($sourceExtra->announcementUntilDate) {
                    $competition->submission_until = Carbon::createFromTimestamp($sourceExtra->announcementUntilDate);
                }

                if ($sourceExtra->announcementRefreshDate) {
                    $competition->information_request_until = Carbon::createFromTimestamp($sourceExtra->announcementRefreshDate);
                }

                if ($sourceExtra->announcementAbgabefrist) {
                    $competition->deadline = Carbon::createFromTimestamp($sourceExtra->announcementAbgabefrist);
                }

                if ($sourceExtra->announcementAbgabePlaene) {
                    $competition->plans_deadline = Carbon::createFromTimestamp($sourceExtra->announcementAbgabePlaene);
                }

                if ($sourceExtra->announcementAbgabeModell) {
                    $competition->model_deadline = Carbon::createFromTimestamp($sourceExtra->announcementAbgabeModell);
                }

                if ($sourceExtra->announcementJuryDate) {
                    $competition->jury_date = Carbon::createFromTimestamp($sourceExtra->announcementJuryDate);
                }

                if ($sourceExtra->announcementBekanntgabe) {
                    $competition->announcement_date = Carbon::createFromTimestamp($sourceExtra->announcementBekanntgabe);
                }

                if ($sourceExtra->announcementBewerbungsfrist) {
                    $competition->application_deadline = Carbon::createFromTimestamp($sourceExtra->announcementBewerbungsfrist);
                }

                $competition->official_number = $sourceExtra->announcementAmtsblattnummer;

                $competition->meta_description = $sourceExtra->seoDescription;
                // $competition->note = is_array($note) ? $note[0] : $note;
                $competition->content = $sourceExtraStore->announcementOriginalHtml;
                $competition->aditional_content = $sourceExtraStore->announcementAdditionHtml;
            }

            $competition->save();

            if ($procedureType) {
                $competition->procedureTypes()->sync([$procedureType->id => ['position' => 1]]);
            }

            if ($sourceExtra && $sourceExtra->announcementCpv) {
                $cpvObjectIds = [];
                foreach (explode(',', $sourceExtra->announcementCpv) as $cpvObjectId) {
                    if (!$cpvObjectId) {
                        continue;
                    }
                    $cpvObjectIds[] = mb_substr($cpvObjectId, 7);
                }
                $codes = $this->connection->table('object_query_43')->whereIn('oo_id', $cpvObjectIds)->get()->pluck('cpvCode');
                $cpvIds = Cpv::whereIn('full_code', $codes)->get()->pluck('id');
                $competition->cpvs()->sync($cpvIds);
            }

            $wo = new WebsiteObject();
            $wo->object_id = $competition->id;
            $wo->object_type = Competition::class;
            $wo->content_type = 'competition';
            $wo->save();

            $languages = LaravelLocalization::getSupportedLanguagesKeys();
            foreach ($languages as $lang) {
                $competitionLanguage = new CompetitionLanguage();
                $competitionLanguage->competition_id = $competition->id;
                $competitionLanguage->language_id = $lang;
                $competitionLanguage->title = mb_substr($source->title, 0, 255);
                $competitionLanguage->save();

                $wol = new WebsiteObjectLanguage();
                $wol->website_object_id = $wo->id;
                $wol->slug = $source->seoUrl . '-' . $competitionObjectId;
                $wol->uri = "{$this->competitionBaseUri[$lang]}/{$wol->slug}";

                if ($sourceObject->o_published) {
                    $wol->status = WebsiteObject::STATUS_PUBLISHED;
                } else {
                    $wol->status = WebsiteObject::STATUS_DRAFT;
                }

                $wol->wo_language_id = $lang;
                $wol->save();
            }

            $contentType = ContentTypes::find('competition');
            ProcessSearch::dispatch($contentType, $competition);

            DB::commit();
            Log::info('Competition imported successfully: ' . $competitionObjectId . ' (' . $competition->wa_id . ')');
            return $competition;
        } catch (Throwable $e) {
            DB::rollBack();
            Log::error('Error Importing ' . $competitionObjectId);
            report($e);
            return null;
        }
    }

    /**
     * Import a tracked result for a competition from Pimcore.
     *
     * @param integer $competitionObjectId
     * @param Competition $competition
     * @return void
     */
    public function importTrackedResult(int $competitionObjectId, Competition $competition): void
    {
        $source = $this->connection->table('object_brick_query_RealisierungWeiterverfolgt_3')
            ->where('o_id', $competitionObjectId)->first();
        $sourceStore = $this->connection->table('object_brick_store_RealisierungWeiterverfolgt_3')
            ->where('o_id', $competitionObjectId)->first();

        if (!$source) {
            Log::info('No Tracked Result found for ID ' . $competitionObjectId);
            return;
        }

        DB::beginTransaction();
        try {
            $trackedResult = new TrackedResult();
            $trackedResult->competition_id = $competition->id;

            $trackedResult->content = $sourceStore->followedUpTeaser;
            $trackedResult->is_public = $competition->is_public ?? true;

            if ($source->followedUpDate) {
                $trackedResult->updated_date = Carbon::createFromTimestamp($source->followedUpDate);
            }

            if ($source->followedUpPdf__id) {
                $pdfItem = $this->importAsset($source->followedUpPdf__id, $competition->wa_id);
                if ($pdfItem) {
                    $trackedResult->pdfDocument()->associate($pdfItem);
                }
            }

            $trackedResult->save();

            $wo = new WebsiteObject();
            $wo->object_id = $trackedResult->id;
            $wo->object_type = TrackedResult::class;
            $wo->content_type = 'tracked_result';
            $wo->save();

            $languages = LaravelLocalization::getSupportedLanguagesKeys();
            foreach ($languages as $lang) {
                $trackedResultLanguage = new TrackedResultLanguage();
                $trackedResultLanguage->tracked_result_id = $trackedResult->id;
                $trackedResultLanguage->language_id = $lang;
                $trackedResultLanguage->title = mb_substr($competition->title, 0, 255);

                $trackedResultLanguage->save();

                $wol = new WebsiteObjectLanguage();
                $wol->website_object_id = $wo->id;
                $wol->slug = $competition->slug . '-' . $competitionObjectId;
                $wol->uri = "{$this->trackedResultBaseUri[$lang]}/{$wol->slug}";

                if ($competition->websites->first()->status == WebsiteObject::STATUS_PUBLISHED) {
                    $wol->status = WebsiteObject::STATUS_PUBLISHED;
                } else {
                    $wol->status = WebsiteObject::STATUS_DRAFT;
                }

                $wol->wo_language_id = $lang;
                $wol->save();
            }

            // Import images
            if ($source->followedUpImagesProtected) {
                $position = 0;
                foreach (explode(',', $source->followedUpImagesProtected) as $asset) {
                    if (!$asset) {
                        continue;
                    }
                    $asset = explode('|', $asset);
                    if ($asset[0] != 'asset') {
                        continue;
                    }
                    $assetId = intval($asset[1]);
                    $mediaItem = $this->importAsset($assetId, $competition->wa_id);
                    if ($mediaItem) {
                        $trackedResult->images()->attach($mediaItem->id, ['position' => $position++]);
                    }
                }
            }

            $trackedResult->refresh();
            if ($source->mImg) {
                $mediaItem = $this->importAsset($source->mImg, $competition->wa_id);
                if ($mediaItem) {
                    $trackedResult->image()->associate($mediaItem);
                    $trackedResult->save();
                }
            } elseif ($trackedResult->images()->count() > 0) {
                $trackedResult->image()->associate($trackedResult->images()->first());
                $trackedResult->save();
            }

            Log::info('Tracked Result imported successfully: ' . $competitionObjectId . ' (' . $competition->wa_id . ')');
            DB::commit();
        } catch (Throwable $e) {
            DB::rollBack();
            Log::error('Error Importing Tracked Result ' . $competitionObjectId);
            report($e);
        }
    }

    /**
     * Import a result for a competition from Pimcore.
     *
     * @param integer $competitionObjectId
     * @param Competition $competition
     * @return void
     */
    public function importResult(int $competitionObjectId, Competition $competition)
    {
        $source = $this->connection->table('object_brick_query_Ergebnis_3')->where('o_id', $competitionObjectId)->first();
        $sourceCompetition = $this->connection->table('object_query_3')
            ->where('oo_id', $competitionObjectId)
            ->whereNull('TestObject')
            ->first();

        if (!$source) {
            Log::info('No Result found for ID ' . $competitionObjectId);
            return;
        }

        DB::beginTransaction();
        try {
            $result = new Result();
            $result->competition_id = $competition->id;

            if ($source->resultInfo) {
                $result->content = nl2br($source->resultInfo);
            }
            $result->result_search_winner = $source->resultSearchWinner;
            $result->result_date = Carbon::createFromTimestamp($source->resultDate);
            $result->is_public = $competition->is_public ?? true;

            if ($source->sharedResultDate) {
                $result->updated_date = Carbon::createFromTimestamp($source->sharedResultDate);
            }

            if ($source->resultPdf__id) {
                $pdfItem = $this->importAsset($source->resultPdf__id, $competition->wa_id);
                if ($pdfItem) {
                    $result->pdfDocument()->associate($pdfItem);
                }
            }

            $result->save();

            $wo = new WebsiteObject();
            $wo->object_id = $result->id;
            $wo->object_type = Result::class;
            $wo->content_type = 'result';
            $wo->save();

            // Map building types
            if ($sourceCompetition->buildingTypes) {
                $buildingTypes = explode(',', $sourceCompetition->buildingTypes);

                $buildingTypeIds = array_map(function ($buildingType) {
                    if (!$buildingType) {
                        return null;
                    }
                    $buildingTypeId = explode('|', $buildingType)[1];
                    return $this->buildingTypesMapping[$buildingTypeId] ?? null;
                }, $buildingTypes);

                if ($result) {
                    $result->buildingTypes()->sync(array_filter($buildingTypeIds));
                }
            }

            $languages = LaravelLocalization::getSupportedLanguagesKeys();
            foreach ($languages as $lang) {
                $resultLanguage = new ResultLanguage();
                $resultLanguage->result_id = $result->id;
                $resultLanguage->language_id = $lang;
                $resultLanguage->title = $competition->title;

                $resultLanguage->save();

                $wol = new WebsiteObjectLanguage();
                $wol->website_object_id = $wo->id;
                $wol->slug = $competition->slug . '-' . $competitionObjectId;
                $wol->uri = "{$this->resultBaseUri[$lang]}/{$wol->slug}";

                if ($competition->websites->first()->status == WebsiteObject::STATUS_PUBLISHED) {
                    $wol->status = WebsiteObject::STATUS_PUBLISHED;
                } else {
                    $wol->status = WebsiteObject::STATUS_DRAFT;
                }

                $wol->wo_language_id = $lang;
                $wol->save();
            }

            $this->importResultWinners($competitionObjectId, $result);

            // Import images
            if ($source->resultImagesProtected) {
                $position = 0;
                foreach (explode(',', $source->resultImagesProtected) as $asset) {
                    if (!$asset) {
                        continue;
                    }
                    $asset = explode('|', $asset);
                    if ($asset[0] != 'asset') {
                        continue;
                    }
                    $assetId = intval($asset[1]);
                    $mediaItem = $this->importAsset($assetId, $competition->wa_id);

                    if ($mediaItem) {
                        $result->images()->attach($mediaItem->id, ['position' => $position++]);
                    }
                }
            }

            $result->refresh();
            if ($source->mImg) {
                $mediaItem = $this->importAsset($source->mImg, $competition->wa_id);
                if ($mediaItem) {
                    $result->image()->associate($mediaItem);
                    $result->save();
                }
            } elseif ($result->images()->count() > 0) {
                $result->image()->associate($result->images()->first());
                $result->save();
            } elseif ($result->winners()->count() > 0) {
                $firstWinner = $result->winners()->first();
                if ($firstWinner->images()->count() > 0) {
                    $result->image()->associate($firstWinner->images()->first());
                    $result->save();
                }
            }

            // Other Dates
            for ($idx = 1; $idx <= 4; $idx++) {
                $dateLabelField = "resultMoreDates__date$idx#labelname";
                $dateField = "resultMoreDates__date$idx#freedate";
                if ($source->$dateLabelField && $source->$dateField) {
                    $resultDate = new ResultDate();
                    $resultDate->result_id = $result->id;
                    $resultDate->date = mb_substr($source->$dateField, 0, 100);
                    $resultDate->save();

                    $wo = new WebsiteObject();
                    $wo->object_id = $resultDate->id;
                    $wo->object_type = ResultDate::class;
                    $wo->content_type = 'result_date';
                    $wo->save();

                    $languages = LaravelLocalization::getSupportedLanguagesKeys();
                    foreach ($languages as $lang) {
                        $resultDateLanguage = new ResultDateLanguage();
                        $resultDateLanguage->result_date_id = $resultDate->id;
                        $resultDateLanguage->language_id = $lang;
                        $resultDateLanguage->title = mb_substr($source->$dateLabelField, 0, 255);

                        $resultDateLanguage->save();

                        $wol = new WebsiteObjectLanguage();
                        $wol->website_object_id = $wo->id;
                        $wol->wo_language_id = $lang;
                        $wol->save();
                    }
                }
            }

            $contentType = ContentTypes::find('result');
            ProcessSearch::dispatch($contentType, $result);

            Log::info('Result imported successfully: ' . $competitionObjectId . ' (' . $competition->wa_id . ')');
            DB::commit();
        } catch (Throwable $e) {
            DB::rollBack();
            Log::error('Error Importing ' . $competitionObjectId);
            report($e);
        }
    }

    /**
     * Import result winners from Pimcore.
     *
     * @param integer $competitionObjectId
     * @param Result $result
     * @return void
     */
    public function importResultWinners(int $competitionObjectId, Result $result)
    {
        $sourceWinners = $this->connection->table('object_collection_preistraeger_3')
            ->where('o_id', $competitionObjectId)
            ->orderBy('index', 'asc')
            ->get();

        foreach ($sourceWinners as $sourceWinner) {
            $resultWinner = new ResultWinner();
            $resultWinner->result_id = $result->id;
            $resultWinner->name = mb_substr($sourceWinner->positionArchitectsText, 0, 1000);
            $resultWinner->legacy_other = mb_substr($sourceWinner->positionMore, 0, 1000);
            $resultWinner->legacy_name2 = mb_substr($sourceWinner->positionArchitects2Text, 0, 1000);
            $resultWinner->legacy_other2 = mb_substr($sourceWinner->positionMore2, 0, 1000);
            $resultWinner->is_import = true;
            $resultWinner->save();

            $wo = new WebsiteObject();
            $wo->object_id = $resultWinner->id;
            $wo->object_type = ResultWinner::class;
            $wo->content_type = 'result_winner';
            $wo->save();

            $languages = LaravelLocalization::getSupportedLanguagesKeys();
            foreach ($languages as $lang) {
                $winnerLanguage = new ResultWinnerLanguage();
                $winnerLanguage->result_winner_id = $resultWinner->id;
                $winnerLanguage->language_id = $lang;
                $winnerLanguage->title = mb_substr($sourceWinner->positionTitle, 0, 255);

                $winnerLanguage->save();

                $wol = new WebsiteObjectLanguage();
                $wol->website_object_id = $wo->id;
                $wol->wo_language_id = $lang;
                $wol->save();
            }
            /*
            if ($sourceWinner->positionArchitectsText) {
                $this->importWinnerEntity($resultWinner, $sourceWinner->positionArchitectsText, $sourceWinner->positionMore);
            }

            if ($sourceWinner->positionArchitects2Text) {
                $this->importWinnerEntity($resultWinner, $sourceWinner->positionArchitects2Text, $sourceWinner->positionMore2);
            }
            */

            $winnerImages = $this->connection->table('object_relations_3')
                ->where('src_id', $competitionObjectId)
                ->where('fieldname', 'positionImages')
                ->where('ownername', 'winners')
                ->where('ownertype', 'fieldcollection')
                ->where('position', $sourceWinner->index)
                ->orderBy('index', 'asc')
                ->get();

            foreach ($winnerImages as $idx => $winnerImage) {
                $mediaItem = $this->importAsset($winnerImage->dest_id, $result->competition->wa_id);
                if ($mediaItem) {
                    $resultWinner->images()->attach($mediaItem->id, ['position' => $idx]);
                }
            }
        }
    }

    /**
     * Import a winner entity for a result winner.
     *
     * @param ResultWinner $resultWinner
     * @param string $architect
     * @param string|null $other
     * @return void
     */
    public function importWinnerEntity(ResultWinner $resultWinner, string $architect, string $other = null)
    {
        $resultEntity = new ResultEntity();
        $resultEntity->result_winner_id = $resultWinner->id;
        $resultEntity->name = mb_substr($architect, 0, 255);
        if ($other) {
            $resultEntity->content = $other;
        }

        $resultEntity->save();

        $wo = new WebsiteObject();
        $wo->object_id = $resultEntity->id;
        $wo->object_type = ResultEntity::class;
        $wo->content_type = 'result_entity';
        $wo->save();

        $languages = LaravelLocalization::getSupportedLanguagesKeys();
        foreach ($languages as $lang) {
            $entityLanguage = new ResultEntityLanguage();
            $entityLanguage->result_entity_id = $resultEntity->id;
            $entityLanguage->language_id = $lang;
            $entityLanguage->title = mb_substr($architect, 0, 255);

            $entityLanguage->save();

            $wol = new WebsiteObjectLanguage();
            $wol->website_object_id = $wo->id;
            $wol->wo_language_id = $lang;
            $wol->save();
        }
    }

    protected function getBuildingTypeMapping(): array
    {
        $mapping = [];
        $localMapping = [];
        $buildingTypes = $this->connection->table('object_query_13')->get();
        $localBuildingTypes = BuildingType::full()->get();
        foreach ($localBuildingTypes as $type) {
            $typeNumber = explode(' ', $type->title)[0];
            $localMapping[$typeNumber] = $type->id;
        }
        foreach ($buildingTypes as $type) {
            $typeNumber = explode(' ', $type->title)[0];
            $mapping[$type->oo_id] = $localMapping[$typeNumber] ?? null;
        }
        return $mapping;
    }
}
