<?php

namespace App\Payment\Entity;

use App\Appointment\Entity\Appointment;
use App\Auth\Entity\User;
use Doctrine\ORM\Mapping as ORM;
use App\Payment\Repository\PaymentRepository;
use Symfony\Component\Uid\Uuid;

#[ORM\Entity(repositoryClass: PaymentRepository::class)]
#[ORM\Table(name: 'payments')]
#[ORM\Index(columns: ['order_id'],     name: 'idx_payments_order')]
#[ORM\Index(columns: ['user_id'],      name: 'idx_payments_user')]
class Payment
{
    public const STATUS_PENDING  = 'pending';
    public const STATUS_SUCCESS  = 'success';
    public const STATUS_FAILED   = 'failed';
    public const STATUS_CANCELED = 'canceled';
    public const STATUS_REFUNDED = 'refunded';

    public const TYPE_APPOINTMENT   = 'appointment';
    public const TYPE_SUBSCRIPTION  = 'subscription';
    public const TYPE_SMS_WALLET    = 'sms_wallet';

    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private ?int $id = null;

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

    #[ORM\Column(name: 'order_id', type: 'string', length: 64, unique: true)]
    private string $orderId;

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

    #[ORM\ManyToOne(targetEntity: Appointment::class)]
    #[ORM\JoinColumn(name: 'appointment_id', referencedColumnName: 'id', nullable: true, onDelete: 'SET NULL')]
    private ?Appointment $appointment = null;

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

    #[ORM\Column(type: 'string', length: 30)]
    private string $status = self::STATUS_PENDING;

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

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

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

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

    #[ORM\Column(name: 'frontend_address', type: 'string', length: 500, nullable: true)]
    private ?string $frontendAddress = null;

    #[ORM\Column(name: 'callback_ip', type: 'string', length: 45, nullable: true)]
    private ?string $callbackIp = null;

    #[ORM\Column(type: 'json', nullable: true)]
    private ?array $metadata = null;

    #[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, int $amountRials, string $gateway, string $type, string $frontendAddress = '')
    {
        $this->uuid            = Uuid::v4()->toRfc4122();
        $this->orderId         = 'ORD-' . strtoupper(substr(str_replace('-', '', Uuid::v4()->toRfc4122()), 0, 16));
        $this->user            = $user;
        $this->amountRials     = $amountRials;
        $this->gateway         = $gateway;
        $this->type            = $type;
        $this->frontendAddress = $frontendAddress ?: null;
        $this->createdAt       = time();
        $this->updatedAt       = time();
    }

    public function getId(): ?int           { return $this->id; }
    public function getUuid(): string       { return $this->uuid; }
    public function getOrderId(): string    { return $this->orderId; }
    public function getUser(): User         { return $this->user; }
    public function getAppointment(): ?Appointment { return $this->appointment; }
    public function getAmountRials(): int   { return $this->amountRials; }
    public function getStatus(): string     { return $this->status; }
    public function getGateway(): string    { return $this->gateway; }
    public function getType(): string       { return $this->type; }
    public function getGatewayToken(): ?string { return $this->gatewayToken; }
    public function getReferenceId(): ?string  { return $this->referenceId; }
    public function getFrontendAddress(): ?string { return $this->frontendAddress; }
    public function getCallbackIp(): ?string   { return $this->callbackIp; }
    public function getMetadata(): ?array      { return $this->metadata; }

    public function setAppointment(?Appointment $a): self    { $this->appointment = $a; return $this; }
    public function setMetadata(?array $metadata): self      { $this->metadata = $metadata; $this->touch(); return $this; }
    public function setGatewayToken(?string $t): self        { $this->gatewayToken = $t; $this->touch(); return $this; }
    public function setReferenceId(?string $r): self         { $this->referenceId = $r; $this->touch(); return $this; }
    public function setStatus(string $s): self               { $this->status = $s; $this->touch(); return $this; }
    public function setCallbackIp(?string $ip): self         { $this->callbackIp = $ip; $this->touch(); return $this; }
    public function setFrontendAddress(?string $a): self     { $this->frontendAddress = $a ?: null; $this->touch(); return $this; }

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

    public function toArray(): array
    {
        return [
            'uuid'             => $this->uuid,
            'order_id'         => $this->orderId,
            'amount_rials'     => $this->amountRials,
            'status'           => $this->status,
            'gateway'          => $this->gateway,
            'type'             => $this->type,
            'reference_id'     => $this->referenceId,
            'appointment_uuid' => $this->appointment?->getUuid(),
            'created_at'       => $this->createdAt,
        ];
    }
}
