<?php

namespace App\Domains\Tenant\Services;

use App\Domains\Attachable\Models\Attachment;
use App\Domains\Attachable\Services\AttachmentService;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class TenantService
{
    public function __construct(
        protected AttachmentService $attachmentService,
        protected WebsiteExtraService $websiteExtraService,
    ) {}

    /**
     * Create a new tenant and store its logos.
     *
     * @param  array<string, mixed>  $data
     */
    public function create(array $data): Tenant
    {
        return DB::transaction(function () use ($data): Tenant {
            $headerLogo = $data['header_logo'] ?? null;
            $footerLogo = $data['footer_logo'] ?? null;
            $favicon = $data['favicon'] ?? null;
            $headerBackgroundImage = $data['header_bg_image'] ?? null;
            $footerBackgroundImage = $data['footer_bg_image'] ?? null;
            $socialMedia = $data['social_media'] ?? [];
            $extras = $data['extras'] ?? [];

            unset(
                $data['header_logo'],
                $data['footer_logo'],
                $data['favicon'],
                $data['header_bg_image'],
                $data['footer_bg_image'],
                $data['social_media'],
                $data['extras'],
            );

            $headerAttachmentId = null;
            if ($headerLogo) {
                $attachment = Str::isUuid($headerLogo)
                    ? Attachment::query()->where('key', $headerLogo)->first()
                    : $this->attachmentService->store($headerLogo, 'tenants');

                if ($attachment) {
                    $headerAttachmentId = $attachment->id;
                }
            }

            $footerAttachmentId = null;
            if ($footerLogo) {
                $attachment = Str::isUuid($footerLogo)
                    ? Attachment::query()->where('key', $footerLogo)->first()
                    : $this->attachmentService->store($footerLogo, 'tenants');

                if ($attachment) {
                    $footerAttachmentId = $attachment->id;
                }
            }

            $data['header_logo_id'] = $headerAttachmentId;
            $data['footer_logo_id'] = $footerAttachmentId;
            $data['favicon_id'] = $this->storeTenantImage($favicon);
            $data['header_bg_image_id'] = $this->storeTenantImage($headerBackgroundImage);
            $data['footer_bg_image_id'] = $this->storeTenantImage($footerBackgroundImage);

            /** @var Tenant $tenant */
            $tenant = Tenant::query()->create($data);
            $this->syncSocialMedia($tenant, $socialMedia);
            $this->websiteExtraService->createForTenant($tenant, $extras);

            return $tenant;
        });
    }

    /**
     * Update an existing tenant and store new logos if uploaded.
     *
     * @param  array<string, mixed>  $data
     */
    public function update(Tenant $tenant, array $data): Tenant
    {
        return DB::transaction(function () use ($tenant, $data): Tenant {
            $hasHeaderLogoKey = array_key_exists('header_logo', $data);
            $hasFooterLogoKey = array_key_exists('footer_logo', $data);
            $hasFaviconKey = array_key_exists('favicon', $data);
            $hasHeaderBackgroundImageKey = array_key_exists('header_bg_image', $data);
            $hasFooterBackgroundImageKey = array_key_exists('footer_bg_image', $data);
            $hasSocialMediaKey = array_key_exists('social_media', $data);
            $headerLogo = $data['header_logo'] ?? null;
            $footerLogo = $data['footer_logo'] ?? null;
            $favicon = $data['favicon'] ?? null;
            $headerBackgroundImage = $data['header_bg_image'] ?? null;
            $footerBackgroundImage = $data['footer_bg_image'] ?? null;
            $socialMedia = $data['social_media'] ?? [];

            unset(
                $data['header_logo'],
                $data['footer_logo'],
                $data['favicon'],
                $data['header_bg_image'],
                $data['footer_bg_image'],
                $data['social_media']
            );

            $tenant->fill($data);

            if ($hasHeaderLogoKey) {
                if ($headerLogo) {
                    $attachment = Str::isUuid($headerLogo)
                        ? Attachment::query()->where('key', $headerLogo)->first()
                        : $this->attachmentService->store($headerLogo, 'tenants');

                    if ($attachment) {
                        $tenant->header_logo_id = $attachment->id;
                    } else {
                        $tenant->header_logo_id = null;
                    }
                } else {
                    $tenant->header_logo_id = null;
                }
            }

            if ($hasFooterLogoKey) {
                if ($footerLogo) {
                    $attachment = Str::isUuid($footerLogo)
                        ? Attachment::query()->where('key', $footerLogo)->first()
                        : $this->attachmentService->store($footerLogo, 'tenants');

                    if ($attachment) {
                        $tenant->footer_logo_id = $attachment->id;
                    } else {
                        $tenant->footer_logo_id = null;
                    }
                } else {
                    $tenant->footer_logo_id = null;
                }
            }

            if ($hasFaviconKey) {
                $tenant->favicon_id = $this->storeTenantImage($favicon);
            }

            if ($hasHeaderBackgroundImageKey) {
                $tenant->header_bg_image_id = $this->storeTenantImage($headerBackgroundImage);
            }

            if ($hasFooterBackgroundImageKey) {
                $tenant->footer_bg_image_id = $this->storeTenantImage($footerBackgroundImage);
            }

            $tenant->save();

            if ($hasSocialMediaKey) {
                $this->syncSocialMedia($tenant, $socialMedia);
            }

            return $tenant;
        });
    }

    /**
     * @param  array<int, array{code: string, url: string, orden?: int}>  $socialMedia
     */
    private function syncSocialMedia(Tenant $tenant, array $socialMedia): void
    {
        $associations = [];

        foreach (array_values($socialMedia) as $index => $item) {
            $associations[$item['code']] = [
                'url' => $item['url'],
                'orden' => $item['orden'] ?? $index,
            ];
        }

        $tenant->socialMedia()->sync($associations);
        $tenant->unsetRelation('socialMedia');
    }

    private function storeTenantImage(mixed $image): ?int
    {
        if (! $image) {
            return null;
        }

        $attachment = is_string($image) && Str::isUuid($image)
            ? Attachment::query()->where('key', $image)->first()
            : $this->attachmentService->store($image, 'tenants');

        return $attachment?->id;
    }
}
