<?php

namespace App\Representation\Entity;

use App\Auth\Entity\User;
use App\Location\Entity\City;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use App\Representation\Repository\RepresentationRepository;
use Symfony\Component\Uid\Uuid;

#[ORM\Entity(repositoryClass: RepresentationRepository::class)]
#[ORM\Table(name: 'representations')]
class Representation
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private ?int $id = null;

    #[ORM\Column(type: 'string', length: 36, unique: true)]
    private string $uuid;

    #[ORM\OneToOne(targetEntity: User::class)]
    #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
    private User $user;

    #[ORM\Column(type: 'string', length: 255)]
    private string $fullName;

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

    /** @deprecated نگاشت تک-شهری قدیمی؛ منبع حقیقت $cities است. فقط برای BC خوانده می‌شود. */
    #[ORM\Column(name: 'city_id', type: 'integer', nullable: true)]
    private ?int $cityId = null;

    /** @var Collection<int, City> شهرهای تحت پوشش نماینده */
    #[ORM\ManyToMany(targetEntity: City::class)]
    #[ORM\JoinTable(name: 'representation_cities')]
    private Collection $cities;

    /** دامنه اختصاصی نماینده (نرمال‌شده: بدون scheme/www)؛ مبنای کمیسیون دامنه‌محور. */
    #[ORM\Column(type: 'string', length: 255, nullable: true, unique: true)]
    private ?string $domain = null;

    #[ORM\Column(name: 'is_global', type: 'boolean')]
    private bool $isGlobal = false;

    #[ORM\Column(name: 'commission_percent', type: 'decimal', precision: 5, scale: 2)]
    private string $commissionPercent = '10.00';

    /**
     * آرایه‌ی ۰ تا ۲ شماره شبای نماینده.
     * هر آیتم: { id, iban, bank_name, owner_name, verified, created_at }
     */
    #[ORM\Column(name: 'bank_account', type: 'json', nullable: true)]
    private ?array $bankAccount = null;

    #[ORM\Column(type: 'boolean')]
    private bool $active = true;

    #[ORM\Column(name: 'created_at', type: 'integer')]
    private int $createdAt;

    #[ORM\Column(name: 'updated_at', type: 'integer')]
    private int $updatedAt;

    public function __construct(User $user, string $fullName)
    {
        $this->uuid      = Uuid::v4()->toRfc4122();
        $this->user      = $user;
        $this->fullName  = $fullName;
        $this->cities    = new ArrayCollection();
        $this->createdAt = time();
        $this->updatedAt = time();
    }

    /** نرمال‌سازی دامنه: lowercase، حذف scheme/www/پورت/اسلش انتهایی. */
    public static function normalizeDomain(?string $domain): ?string
    {
        if ($domain === null) return null;
        $d = strtolower(trim($domain));
        $d = preg_replace('~^https?://~', '', $d) ?? $d;
        $d = preg_replace('~^www\.~', '', $d) ?? $d;
        $d = explode('/', $d)[0];
        $d = explode(':', $d)[0];
        return $d === '' ? null : $d;
    }

    public function getId(): ?int              { return $this->id; }
    public function getUuid(): string          { return $this->uuid; }
    public function getUser(): User            { return $this->user; }
    public function getFullName(): string      { return $this->fullName; }
    public function getMobileNumber(): ?string { return $this->mobileNumber; }
    public function getCityId(): ?int          { return $this->cityIds()[0] ?? $this->cityId; }
    /** @return Collection<int, City> */
    public function getCities(): Collection    { return $this->cities; }
    /** @return int[] */
    public function cityIds(): array           { return array_values(array_map(fn(City $c) => (int) $c->getId(), $this->cities->toArray())); }
    public function getDomain(): ?string       { return $this->domain; }
    public function isGlobal(): bool           { return $this->isGlobal; }
    public function getCommissionPercent(): string { return $this->commissionPercent; }
    public function getBankAccount(): ?array   { return $this->bankAccount; }
    public function isActive(): bool           { return $this->active; }

    public function setFullName(string $v): self           { $this->fullName = $v; $this->touch(); return $this; }
    public function setMobileNumber(?string $v): self      { $this->mobileNumber = $v; $this->touch(); return $this; }
    public function setCityId(?int $v): self               { $this->cityId = $v; $this->touch(); return $this; }
    /** @param City[] $cities */
    public function setCities(array $cities): self
    {
        $this->cities->clear();
        foreach ($cities as $city) {
            if (!$this->cities->contains($city)) $this->cities->add($city);
        }
        $this->touch();
        return $this;
    }
    public function setDomain(?string $v): self            { $this->domain = self::normalizeDomain($v); $this->touch(); return $this; }
    public function setIsGlobal(bool $v): self             { $this->isGlobal = $v; $this->touch(); return $this; }
    public function setCommissionPercent(string $v): self  { $this->commissionPercent = $v; $this->touch(); return $this; }
    public function setBankAccount(?array $v): self        { $this->bankAccount = $v; $this->touch(); return $this; }
    public function setActive(bool $v): self               { $this->active = $v; $this->touch(); return $this; }

    /** @return array<int,array<string,mixed>> */
    public function getIbans(): array { return $this->bankAccount ?? []; }

    /**
     * افزودن یک شبا (حداکثر ۲). id خودکار تولید می‌شود.
     * @param array{iban:string,bank_name:?string,owner_name:?string,verified?:bool} $iban
     */
    public function addIban(array $iban): self
    {
        $ibans = $this->getIbans();
        if (count($ibans) >= 2) {
            throw new \DomainException('iban_limit');
        }
        $ibans[] = [
            'id'         => Uuid::v4()->toRfc4122(),
            'iban'       => $iban['iban'],
            'bank_name'  => $iban['bank_name'] ?? null,
            'owner_name' => $iban['owner_name'] ?? null,
            'verified'   => $iban['verified'] ?? false,
            'created_at' => time(),
        ];
        $this->bankAccount = $ibans;
        $this->touch();
        return $this;
    }

    public function removeIban(string $id): self
    {
        $this->bankAccount = array_values(array_filter(
            $this->getIbans(),
            fn(array $i) => ($i['id'] ?? null) !== $id
        ));
        $this->touch();
        return $this;
    }

    /** @return array<string,mixed>|null یک شبای تأییدشده با این id */
    public function findVerifiedIban(string $id): ?array
    {
        foreach ($this->getIbans() as $iban) {
            if (($iban['id'] ?? null) === $id && ($iban['verified'] ?? false)) {
                return $iban;
            }
        }
        return null;
    }

    private function touch(): void { $this->updatedAt = time(); }

    public function toArray(): array
    {
        return [
            'uuid'               => $this->uuid,
            'full_name'          => $this->fullName,
            'mobile_number'      => $this->mobileNumber,
            'city_id'            => $this->getCityId(),
            'city_ids'           => $this->cityIds(),
            'cities'             => array_values(array_map(
                fn(City $c) => ['id' => (int) $c->getId(), 'name' => $c->getName()],
                $this->cities->toArray(),
            )),
            'domain'             => $this->domain,
            'is_global'          => $this->isGlobal,
            'commission_percent' => $this->commissionPercent,
            'bank_account'       => $this->bankAccount,
            'active'             => $this->active,
            'created_at'         => $this->createdAt,
        ];
    }
}
