<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\Entity]
class PageConfig implements TenantAwareInterface
{
    use TenantAwareTrait;

    #[ORM\Id]
    #[ORM\Column(type: UuidType::NAME)]
    #[ORM\GeneratedValue(strategy: 'CUSTOM')]
    #[ORM\CustomIdGenerator(class: UuidGenerator::class)]
    private Uuid $id;

    #[Assert\NotBlank]
    #[ORM\Column(type: 'string', length: 255)]
    private string $pageTitle = 'Ferienpass';

    #[Assert\NotBlank]
    #[Assert\Email]
    #[ORM\Column(type: 'string', length: 255)]
    private string $adminEmail = 'admin@ferienpass.online';

    #[ORM\Column(type: 'string', length: 10, options: ['default' => 'de'])]
    private string $language = 'de';

    #[ORM\Column(type: 'string', length: 50, options: ['default' => 'd.m.Y'])]
    private string $dateFormat = 'd.m.Y';

    #[ORM\Column(type: 'string', length: 100, options: ['default' => 'Europe/Berlin'])]
    private string $timezone = 'Europe/Berlin';

    /** How printed and exported participant lists are ordered. */
    #[Assert\Choice(choices: ['firstname', 'lastname'])]
    #[ORM\Column(type: 'string', length: 20, options: ['default' => 'lastname'])]
    private string $participantListSort = 'lastname';

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $adminEmailName = null;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $replyToEmail = null;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $replyToName = null;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $friendsBooking = false;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $preferredPostalCodes = null;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $requirePostalAddress = false;

    #[Assert\Regex(pattern: '/^\d+\s+(day|days|week|weeks|month|months|year|years)$/i', message: 'Bitte einen gültigen Zeitraum angeben, z. B. "30 days" oder "12 months".')]
    #[ORM\Column(type: 'string', length: 20, nullable: true)]
    private ?string $eraseDataPeriod = null;

    #[ORM\Column(type: 'string', length: 20, nullable: true)]
    private ?string $attendanceRemindPeriod = null;

    /**
     * Whether this municipality uses the payment system at all — receipts,
     * debtors, manual and cash payments.
     *
     * Configuring an online payment provider switches payments on by itself
     * ({@see \Ferienpass\CoreBundle\Payments\PaymentSystem}); this covers the
     * municipality that takes payments without one.
     */
    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $paymentsEnabled = false;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $paymentAllowSelect = false;

    #[ORM\Column(type: 'string', length: 20, nullable: true)]
    private ?string $ageTolerance = null;

    #[ORM\Column(type: 'string', length: 20, nullable: true)]
    private ?string $withdrawGracePeriod = null;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $noWithdrawAfterGracePeriod = false;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $noWithdrawAfterApplicationDeadline = false;

    #[Assert\Regex(pattern: '/^[\p{L}\p{N}\-_\/\.]+$/u', message: 'Der Präfix darf nur Buchstaben, Ziffern und die Zeichen - _ / . enthalten.')]
    #[ORM\Column(type: 'string', length: 20, nullable: true)]
    private ?string $receiptNumberPrefix = null;

    #[ORM\Column(type: 'boolean', options: ['default' => false])]
    private bool $remindAttendance = false;

    #[Assert\CssColor(formats: [Assert\CssColor::HEX_LONG, Assert\CssColor::HEX_SHORT])]
    #[ORM\Column(type: 'string', length: 30, nullable: true)]
    private ?string $colorPrimary = null;

    /**
     * The installation's logo, stored in the `logos` virtual filesystem exactly
     * like a host's.
     *
     * It lives in the database rather than in the repository because branding
     * has to follow the *tenant*, and a worker rendering a queued e-mail has no
     * request, no host and no per-tenant template path to resolve one from — it
     * only has the tenant its message is stamped with.
     * {@see \Ferienpass\CoreBundle\EventListener\EmailLogoListener} embeds it.
     */
    #[ORM\ManyToOne(targetEntity: DbafsLogo::class)]
    #[ORM\JoinColumn(name: 'logo_id', referencedColumnName: 'uuid')]
    private ?DbafsLogo $logo = null;

    // ── Imprint / data controller (verantwortliche Stelle) ──────────────
    // The responsible body shown on the public "Datennutzung" page. Has
    // account-wide access to all data for as long as the account exists.

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $imprintName = null;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $imprintDepartment = null;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $imprintStreet = null;

    #[ORM\Column(type: 'string', length: 32, nullable: true)]
    private ?string $imprintPostalCode = null;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $imprintCity = null;

    // Retention window during which a host keeps access to a participant's
    // data, counted from the offer's end date. Only used as a FALLBACK when
    // the offer's edition has no "publish_lists" (Teilnahmelisten verfügbar)
    // task to gate access. Distinct from {@see $eraseDataPeriod}, which
    // governs deletion of the whole account. Format: "<number> <unit>".
    #[Assert\Regex(pattern: '/^\d+\s+(day|days|week|weeks|month|months|year|years)$/i', message: 'Bitte einen gültigen Zeitraum angeben, z. B. "6 months".')]
    #[ORM\Column(type: 'string', length: 20, nullable: true)]
    private ?string $hostDataRetentionPeriod = null;

    public function __construct(?Uuid $uuid = null)
    {
        if ($uuid instanceof Uuid) {
            $this->id = $uuid;
        }
    }

    public function getId(): Uuid
    {
        return $this->id;
    }

    public function getColorPrimary(): ?string
    {
        return $this->colorPrimary;
    }

    public function setColorPrimary(?string $colorPrimary): void
    {
        $this->colorPrimary = $colorPrimary;
    }

    public function getLogo(): ?DbafsLogo
    {
        return $this->logo;
    }

    public function setLogo(?DbafsLogo $logo): void
    {
        $this->logo = $logo;
    }

    public function getPageTitle(): string
    {
        return $this->pageTitle;
    }

    public function setPageTitle(string $pageTitle): void
    {
        $this->pageTitle = $pageTitle;
    }

    public function getAdminEmail(): string
    {
        return $this->adminEmail;
    }

    public function setAdminEmail(string $adminEmail): void
    {
        $this->adminEmail = $adminEmail;
    }

    public function getLanguage(): string
    {
        return $this->language;
    }

    public function setLanguage(string $language): void
    {
        $this->language = $language;
    }

    public function getDateFormat(): string
    {
        return $this->dateFormat;
    }

    public function setDateFormat(string $dateFormat): void
    {
        $this->dateFormat = $dateFormat;
    }

    public function getTimezone(): string
    {
        return $this->timezone;
    }

    public function setTimezone(string $timezone): void
    {
        $this->timezone = $timezone;
    }

    public function getParticipantListSort(): string
    {
        return $this->participantListSort;
    }

    public function setParticipantListSort(string $participantListSort): void
    {
        $this->participantListSort = $participantListSort;
    }

    public function getAdminEmailName(): ?string
    {
        return $this->adminEmailName;
    }

    public function setAdminEmailName(?string $adminEmailName): void
    {
        $this->adminEmailName = $adminEmailName;
    }

    public function getReplyToEmail(): ?string
    {
        return $this->replyToEmail;
    }

    public function setReplyToEmail(?string $replyToEmail): void
    {
        $this->replyToEmail = $replyToEmail;
    }

    public function getReplyToName(): ?string
    {
        return $this->replyToName;
    }

    public function setReplyToName(?string $replyToName): void
    {
        $this->replyToName = $replyToName;
    }

    public function isFriendsBooking(): bool
    {
        return $this->friendsBooking;
    }

    public function setFriendsBooking(bool $friendsBooking): void
    {
        $this->friendsBooking = $friendsBooking;
    }

    public function getPreferredPostalCodes(): ?string
    {
        return $this->preferredPostalCodes;
    }

    public function getPreferredPostalCodesArray(): array
    {
        if (null === $this->preferredPostalCodes) {
            return [];
        }

        return array_map('trim', explode(',', $this->preferredPostalCodes));
    }

    public function setPreferredPostalCodes(?string $preferredPostalCodes): void
    {
        $this->preferredPostalCodes = $preferredPostalCodes;
    }

    public function isRequirePostalAddress(): bool
    {
        return $this->requirePostalAddress;
    }

    public function setRequirePostalAddress(bool $requirePostalAddress): void
    {
        $this->requirePostalAddress = $requirePostalAddress;
    }

    public function getEraseDataPeriod(): ?string
    {
        return $this->eraseDataPeriod;
    }

    public function setEraseDataPeriod(?string $eraseDataPeriod): void
    {
        $this->eraseDataPeriod = $eraseDataPeriod;
    }

    public function getAttendanceRemindPeriod(): ?string
    {
        return $this->attendanceRemindPeriod;
    }

    public function setAttendanceRemindPeriod(?string $attendanceRemindPeriod): void
    {
        $this->attendanceRemindPeriod = $attendanceRemindPeriod;
    }

    public function isPaymentsEnabled(): bool
    {
        return $this->paymentsEnabled;
    }

    public function setPaymentsEnabled(bool $paymentsEnabled): void
    {
        $this->paymentsEnabled = $paymentsEnabled;
    }

    public function isPaymentAllowSelect(): bool
    {
        return $this->paymentAllowSelect;
    }

    public function setPaymentAllowSelect(bool $paymentAllowSelect): void
    {
        $this->paymentAllowSelect = $paymentAllowSelect;
    }

    public function getAgeTolerance(): ?string
    {
        return $this->ageTolerance;
    }

    public function setAgeTolerance(?string $ageTolerance): void
    {
        $this->ageTolerance = $ageTolerance;
    }

    public function getWithdrawGracePeriod(): ?string
    {
        return $this->withdrawGracePeriod;
    }

    public function setWithdrawGracePeriod(?string $withdrawGracePeriod): void
    {
        $this->withdrawGracePeriod = $withdrawGracePeriod;
    }

    public function isNoWithdrawAfterGracePeriod(): bool
    {
        return $this->noWithdrawAfterGracePeriod;
    }

    public function setNoWithdrawAfterGracePeriod(bool $noWithdrawAfterGracePeriod): void
    {
        $this->noWithdrawAfterGracePeriod = $noWithdrawAfterGracePeriod;
    }

    public function isNoWithdrawAfterApplicationDeadline(): bool
    {
        return $this->noWithdrawAfterApplicationDeadline;
    }

    public function setNoWithdrawAfterApplicationDeadline(bool $noWithdrawAfterApplicationDeadline): void
    {
        $this->noWithdrawAfterApplicationDeadline = $noWithdrawAfterApplicationDeadline;
    }

    public function getReceiptNumberPrefix(): ?string
    {
        return $this->receiptNumberPrefix;
    }

    public function setReceiptNumberPrefix(?string $receiptNumberPrefix): void
    {
        $this->receiptNumberPrefix = $receiptNumberPrefix;
    }

    public function isRemindAttendance(): bool
    {
        return $this->remindAttendance;
    }

    public function setRemindAttendance(bool $remindAttendance): void
    {
        $this->remindAttendance = $remindAttendance;
    }

    public function getImprintName(): ?string
    {
        return $this->imprintName;
    }

    public function setImprintName(?string $imprintName): void
    {
        $this->imprintName = $imprintName;
    }

    public function getImprintDepartment(): ?string
    {
        return $this->imprintDepartment;
    }

    public function setImprintDepartment(?string $imprintDepartment): void
    {
        $this->imprintDepartment = $imprintDepartment;
    }

    public function getImprintStreet(): ?string
    {
        return $this->imprintStreet;
    }

    public function setImprintStreet(?string $imprintStreet): void
    {
        $this->imprintStreet = $imprintStreet;
    }

    public function getImprintPostalCode(): ?string
    {
        return $this->imprintPostalCode;
    }

    public function setImprintPostalCode(?string $imprintPostalCode): void
    {
        $this->imprintPostalCode = $imprintPostalCode;
    }

    public function getImprintCity(): ?string
    {
        return $this->imprintCity;
    }

    public function setImprintCity(?string $imprintCity): void
    {
        $this->imprintCity = $imprintCity;
    }

    /**
     * The imprint postal address as a single line, e.g.
     * "Stadtring 23, 48529 Nordhorn", or null if no address is configured.
     */
    public function getImprintAddressLine(): ?string
    {
        $cityLine = trim(($this->imprintPostalCode ?? '').' '.($this->imprintCity ?? ''));
        $parts = array_filter([$this->imprintStreet, '' !== $cityLine ? $cityLine : null]);

        return $parts ? implode(', ', $parts) : null;
    }

    public function hasImprint(): bool
    {
        return null !== $this->imprintName && '' !== $this->imprintName;
    }

    public function getHostDataRetentionPeriod(): ?string
    {
        return $this->hostDataRetentionPeriod;
    }

    public function setHostDataRetentionPeriod(?string $hostDataRetentionPeriod): void
    {
        $this->hostDataRetentionPeriod = $hostDataRetentionPeriod;
    }
}
