<?php

namespace MintyPHP\Service\Tenant;

use MintyPHP\Domain\Taxonomy\TenantStatus;
use MintyPHP\Repository\Org\DepartmentRepositoryInterface;
use MintyPHP\Repository\Tenant\TenantRepositoryInterface;
use MintyPHP\Service\Audit\AuditRecorderInterface;
use MintyPHP\Service\Directory\DirectorySettingsGateway;

class TenantService
{
    public function __construct(
        private readonly TenantRepositoryInterface $tenantRepository,
        private readonly DepartmentRepositoryInterface $departmentRepository,
        private readonly DirectorySettingsGateway $settingsGateway,
        private readonly AuditRecorderInterface $systemAuditService
    ) {
    }

    public function list(): array
    {
        return $this->tenantRepository->list();
    }

    public function listPaged(array $options): array
    {
        return $this->tenantRepository->listPaged($options);
    }

    public function findByUuid(string $uuid): ?array
    {
        return $this->tenantRepository->findByUuid($uuid);
    }

    public function findById(int $id): ?array
    {
        return $this->tenantRepository->find($id);
    }

    public function createFromAdmin(array $input, int $currentUserId = 0): array
    {
        $form = $this->sanitizeBase($input);
        $form['status'] = $this->normalizeStatus($form['status'] ?? '');
        $errors = $this->validateBase($form);

        if ($errors) {
            return ['ok' => false, 'errors' => $errors, 'form' => $form];
        }

        // Always UTC — consistency across server timezone changes.
        $statusChangedAt = gmdate('Y-m-d H:i:s');
        $createdId = $this->tenantRepository->create([
            'description' => $form['description'],
            'address' => $form['address'],
            'postal_code' => $form['postal_code'],
            'city' => $form['city'],
            'country' => $form['country'],
            'region' => $form['region'],
            'vat_id' => $form['vat_id'],
            'tax_number' => $form['tax_number'],
            'phone' => $form['phone'],
            'fax' => $form['fax'],
            'email' => $form['email'],
            'support_email' => $form['support_email'],
            'support_phone' => $form['support_phone'],
            'billing_email' => $form['billing_email'],
            'website' => $form['website'],
            'privacy_url' => $form['privacy_url'],
            'imprint_url' => $form['imprint_url'],
            // Appearance is tenant-scoped with explicit, required values. Every
            // tenant has a primary color, a default theme, and an explicit
            // allow-user-theme flag — there is no global fallback to inherit.
            'primary_color' => strtolower($form['primary_color']),
            'default_theme' => $this->settingsGateway->normalizeTheme($form['default_theme']),
            'allow_user_theme' => $form['allow_user_theme'] ? 1 : 0,
            'status' => $form['status'],
            'status_changed_at' => $statusChangedAt,
            'status_changed_by' => $currentUserId > 0 ? $currentUserId : null,
            'created_by' => $currentUserId > 0 ? $currentUserId : null,
        ]);

        if (!$createdId) {
            return ['ok' => false, 'errors' => [t('Tenant can not be created')], 'form' => $form];
        }

        $createdTenant = $this->tenantRepository->find((int) $createdId);
        $uuid = $createdTenant['uuid'] ?? null;
        if (!empty($input['is_default'])) {
            $this->settingsGateway->setDefaultTenantId((int) $createdId);
        }

        $this->systemAuditService->record('admin.tenants.create', 'success', [
            'actor_user_id' => $currentUserId > 0 ? $currentUserId : null,
            'target_type' => 'tenant',
            'target_id' => (int) $createdId,
            'target_uuid' => is_string($uuid) ? $uuid : '',
            'metadata' => ['status' => $form['status']],
        ]);

        return ['ok' => true, 'form' => $form, 'uuid' => $uuid, 'id' => (int) $createdId];
    }

    public function updateFromAdmin(int $tenantId, array $input, int $currentUserId = 0): array
    {
        $form = $this->sanitizeBase($input);
        $form['status'] = $this->normalizeStatus($form['status'] ?? '');
        $errors = $this->validateBase($form);

        if ($errors) {
            return ['ok' => false, 'errors' => $errors, 'form' => $form];
        }

        $existing = $this->tenantRepository->find($tenantId);
        $statusChanged = false;
        if ($existing && isset($existing['status'])) {
            $statusChanged = (string) $existing['status'] !== $form['status'];
        }

        $updateData = [
            'description' => $form['description'],
            'address' => $form['address'],
            'postal_code' => $form['postal_code'],
            'city' => $form['city'],
            'country' => $form['country'],
            'region' => $form['region'],
            'vat_id' => $form['vat_id'],
            'tax_number' => $form['tax_number'],
            'phone' => $form['phone'],
            'fax' => $form['fax'],
            'email' => $form['email'],
            'support_email' => $form['support_email'],
            'support_phone' => $form['support_phone'],
            'billing_email' => $form['billing_email'],
            'website' => $form['website'],
            'privacy_url' => $form['privacy_url'],
            'imprint_url' => $form['imprint_url'],
            'primary_color' => strtolower($form['primary_color']),
            'default_theme' => $this->settingsGateway->normalizeTheme($form['default_theme']),
            'allow_user_theme' => $form['allow_user_theme'] ? 1 : 0,
            'status' => $form['status'],
            'modified_by' => $currentUserId > 0 ? $currentUserId : null,
        ];
        if ($statusChanged) {
            $updateData['status_changed_at'] = gmdate('Y-m-d H:i:s');
            $updateData['status_changed_by'] = $currentUserId > 0 ? $currentUserId : null;
        }

        $updated = $this->tenantRepository->update($tenantId, $updateData);

        if (!$updated) {
            return ['ok' => false, 'errors' => [t('Tenant can not be updated')], 'form' => $form];
        }

        $this->systemAuditService->record('admin.tenants.update', 'success', [
            'actor_user_id' => $currentUserId > 0 ? $currentUserId : null,
            'target_type' => 'tenant',
            'target_id' => $tenantId,
            'target_uuid' => (string) ($existing['uuid'] ?? ''),
            'before' => [
                'status' => $existing['status'] ?? null,
            ],
            'after' => [
                'status' => $form['status'],
            ],
        ]);

        return ['ok' => true, 'form' => $form];
    }

    public function deleteByUuid(string $uuid): array
    {
        $uuid = trim($uuid);
        if ($uuid === '') {
            return ['ok' => false, 'status' => 404, 'error' => 'not_found'];
        }

        $tenant = $this->tenantRepository->findByUuid($uuid);
        if (!$tenant || !isset($tenant['id'])) {
            return ['ok' => false, 'status' => 404, 'error' => 'not_found'];
        }

        $tenantId = (int) $tenant['id'];
        // Block deletion if departments exist — orphaned departments would break user assignments.
        if ($this->departmentRepository->countByTenantId($tenantId) > 0) {
            return ['ok' => false, 'status' => 409, 'error' => 'tenant_has_departments'];
        }

        $deleted = $this->tenantRepository->delete($tenantId);
        if (!$deleted) {
            return ['ok' => false, 'status' => 500, 'error' => 'delete_failed'];
        }

        $this->systemAuditService->record('admin.tenants.delete', 'success', [
            'target_type' => 'tenant',
            'target_id' => $tenantId,
            'target_uuid' => (string) ($tenant['uuid'] ?? ''),
        ]);

        return ['ok' => true, 'tenant' => $tenant];
    }

    private function sanitizeBase(array $input): array
    {
        return [
            'description' => trim((string) ($input['description'] ?? '')),
            'address' => trim((string) ($input['address'] ?? '')),
            'postal_code' => trim((string) ($input['postal_code'] ?? '')),
            'city' => trim((string) ($input['city'] ?? '')),
            'country' => trim((string) ($input['country'] ?? '')),
            'region' => trim((string) ($input['region'] ?? '')),
            'vat_id' => trim((string) ($input['vat_id'] ?? '')),
            'tax_number' => trim((string) ($input['tax_number'] ?? '')),
            'phone' => trim((string) ($input['phone'] ?? '')),
            'fax' => trim((string) ($input['fax'] ?? '')),
            'email' => trim((string) ($input['email'] ?? '')),
            'support_email' => trim((string) ($input['support_email'] ?? '')),
            'support_phone' => trim((string) ($input['support_phone'] ?? '')),
            'billing_email' => trim((string) ($input['billing_email'] ?? '')),
            'website' => trim((string) ($input['website'] ?? '')),
            'privacy_url' => trim((string) ($input['privacy_url'] ?? '')),
            'imprint_url' => trim((string) ($input['imprint_url'] ?? '')),
            'primary_color' => trim((string) ($input['primary_color'] ?? '')),
            'default_theme' => strtolower(trim((string) ($input['default_theme'] ?? ''))),
            'allow_user_theme' => isset($input['allow_user_theme']) ? (bool) $input['allow_user_theme'] : true,
            'status' => trim((string) ($input['status'] ?? '')),
        ];
    }

    private function validateBase(array $form): array
    {
        $errors = [];
        if ($form['description'] === '') {
            $errors[] = t('Description cannot be empty');
        }
        if (TenantStatus::tryNormalize((string) $form['status']) === null) {
            $errors[] = t('Status is invalid');
        }
        if (
            $form['primary_color'] === ''
            || !preg_match('/^#([0-9a-f]{3}|[0-9a-f]{6})$/i', $form['primary_color'])
        ) {
            $errors[] = t('Primary color is invalid');
        }
        if ($form['default_theme'] !== '' && !$this->settingsGateway->isAllowedTheme((string) $form['default_theme'])) {
            $errors[] = t('Default theme is invalid');
        }
        return $errors;
    }

    private function normalizeStatus(string $status): string
    {
        return TenantStatus::normalizeOr($status, TenantStatus::Active)->value;
    }

}
