<?php
declare(strict_types=1);

namespace App\Languages;

use App\Settings\SettingsRepository;
use App\Support\TranslatableException;
use PDO;
use Throwable;

final class LanguageManagementService
{
    public function __construct(
        private readonly PDO $pdo,
        private readonly LanguageRepository $languages,
        private readonly SettingsRepository $settings,
    ) {
    }

    /** @return array{code:string,before:array<string,mixed>,after:array<string,mixed>} */
    public function toggle(string $code): array
    {
        $code = strtolower(str_replace('_', '-', trim($code)));
        $ownsTransaction = !$this->pdo->inTransaction();
        if ($ownsTransaction) $this->pdo->beginTransaction();

        try {
            $statement = $this->pdo->prepare(
                'SELECT code, name, native_name, direction, fallback_locale, is_enabled, sort_order
                 FROM languages WHERE code = :code LIMIT 1 FOR UPDATE'
            );
            $statement->execute(['code' => $code]);
            $before = $statement->fetch(PDO::FETCH_ASSOC);
            if (!is_array($before)) throw new TranslatableException('admin.language_not_found');

            $enable = empty($before['is_enabled']);
            $modeBefore = strtolower(trim((string) $this->settings->get('site.language_mode', 'multilingual')));
            if (!$enable) {
                $publicDefault = strtolower((string) $this->settings->get('site.default_locale', 'ar'));
                $adminDefault = strtolower((string) $this->settings->get('admin.default_locale', $publicDefault));
                if ($code === $publicDefault || $code === $adminDefault) throw new TranslatableException('admin.language_error_default');
                if ($this->languages->fallbackDependents($code) !== []) throw new TranslatableException('admin.language_error_fallback');
                $enabledRows = $this->pdo->query('SELECT code FROM languages WHERE is_enabled = 1 FOR UPDATE')->fetchAll(PDO::FETCH_COLUMN);
                if (count($enabledRows) <= 1) throw new TranslatableException('admin.language_error_last');
            } elseif ($modeBefore === 'single') {
                $this->settings->put('site.language_mode', 'multilingual', 'string');
                $this->settings->put('site.language_switcher_enabled', true, 'boolean');
            }

            $this->languages->save([
                'code' => $code,
                'name' => (string) $before['name'],
                'native_name' => (string) $before['native_name'],
                'direction' => (string) $before['direction'],
                'fallback_locale' => (string) ($before['fallback_locale'] ?? ''),
                'sort_order' => (int) $before['sort_order'],
                'is_enabled' => $enable ? '1' : '',
            ]);
            $after = $this->languages->find($code) ?? [];
            if (!$enable) {
                $this->languages->reassignAdminLocale($code, $adminDefault);
            }
            $before['language_mode'] = $modeBefore;
            $after['language_mode'] = (string) $this->settings->get('site.language_mode', $modeBefore);

            if ($ownsTransaction) $this->pdo->commit();
            return ['code' => $code, 'before' => $before, 'after' => $after];
        } catch (Throwable $throwable) {
            if ($ownsTransaction && $this->pdo->inTransaction()) $this->pdo->rollBack();
            throw $throwable;
        }
    }
}
