<?php

namespace App\Entity;

use DateTime;
use Doctrine\ORM\Mapping as ORM;
use Payum\Core\Model\Payment as BasePayment;
use Ramsey\Uuid\Doctrine\UuidGenerator;

/**
 * @ORM\Entity(repositoryClass="App\Repository\PaymentRepository")
 * @ORM\Table(name="payment")
 */
class Payment extends BasePayment
{
    const TYPE_ACHAT_MONNAIE_ADHERENT = 'achat_monnaie_adherent';
    const TYPE_ACHAT_MONNAIE_PRESTA = 'achat_monnaie_presta';
    const TYPE_COTISATION_ADHERENT = 'cotisation_adherent';
    const TYPE_COTISATION_PRESTA = 'cotisation_presta';
    const TYPE_ADHESION = 'adhesion';
    const TYPE_PAIEMENT_COTISATION_TAV = 'paiement_cotisation_tav';
    const TYPE_PAIEMENT_RECURRENT_COTISATION_TAV = 'paiement_recurrent_cotisation_tav';

    public function __construct()
    {
        parent::__construct();
        $this->created_at = new \DateTime();
    }

    /**
     * @var \Ramsey\Uuid\UuidInterface
     *
     * @ORM\Id
     * @ORM\Column(type="uuid", unique=true)
     * @ORM\GeneratedValue(strategy="CUSTOM")
     * @ORM\CustomIdGenerator(class=UuidGenerator::class)
     */
    protected $id;

    /**
     * @var string|null
     *
     * @ORM\Column(type="string", length=50, nullable=true)
     */
    protected $status;

    /**
     * @var string|null
     *                  JSON array of 'Flux' to persist if payment valid
     *
     * @ORM\Column(type="text", nullable=true)
     */
    protected $flux_data;

    /**
     * @var string|null
     *                  Extra data to persist if payment valid
     *
     * @ORM\Column(type="text", nullable=true)
     */
    protected $extra_data;

    /**
     * @ORM\Column(type="boolean", nullable=True)
     */
    private $isRecurrent;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $recurrenceMonthsCount;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $recurrenceMonthDay;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $recurrenceAmount;

    /**
     * @var string|null
     *
     * @ORM\Column(type="string", length=50, nullable=true)
     */
    protected $startingPaymentAnalysisStatus;

    /**
     * Payment creation datetime.
     *
     * @ORM\Column(type="datetime", nullable=true)
     */
    private $created_at;

    /**
     * @return string
     */
    public function getStatus(): ?string
    {
        return $this->status;
    }

    /**
     * @param string $status
     *
     * @return Payment
     */
    public function setStatus(string $status): self
    {
        $this->status = $status;

        return $this;
    }

    /**
     * @return string
     */
    public function getFluxData(): ?string
    {
        return $this->flux_data;
    }

    /**
     * @param string $flux_data
     *
     * @return Payment
     */
    public function setFluxData(string $flux_data): self
    {
        $this->flux_data = $flux_data;

        return $this;
    }

    /**
     * @return string
     */
    public function getExtraData(): ?string
    {
        return $this->extra_data;
    }

    /**
     * @param string $extra_data
     *
     * @return Payment
     */
    public function setExtraData(string $extra_data): self
    {
        $this->extra_data = $extra_data;

        return $this;
    }

    public function getIsRecurrent(): ?bool
    {
        return $this->isRecurrent;
    }

    public function setIsRecurrent(bool $isRecurrent): self
    {
        $this->isRecurrent = $isRecurrent;

        return $this;
    }

    public function getRecurrenceMonthsCount(): ?int
    {
        return $this->recurrenceMonthsCount;
    }

    public function setRecurrenceMonthsCount(?int $recurrenceMonthsCount): self
    {
        $this->recurrenceMonthsCount = $recurrenceMonthsCount;

        return $this;
    }

    public function getRecurrenceMonthDay(): ?int
    {
        return $this->recurrenceMonthDay;
    }

    public function setRecurrenceMonthDay(?int $recurrenceMonthDay): self
    {
        $this->recurrenceMonthDay = $recurrenceMonthDay;

        return $this;
    }

    public function getRecurrenceAmount(): ?int
    {
        return $this->recurrenceAmount;
    }

    public function setRecurrenceAmount(?int $recurrenceAmount): self
    {
        $this->recurrenceAmount = $recurrenceAmount;

        return $this;
    }

    /**
     * @return string
     */
    public function getStartingPaymentAnalysisStatus(): ?string
    {
        return $this->startingPaymentAnalysisStatus;
    }

    /**
     * @param string $startingPaymentAnalysisStatus
     *
     * @return Payment
     */
    public function setStartingPaymentAnalysisStatus(string $startingPaymentAnalysisStatus): self
    {
        $this->startingPaymentAnalysisStatus = $startingPaymentAnalysisStatus;

        return $this;
    }

    public function getCreatedAt(): ?DateTime
    {
        return $this->created_at;
    }

    /**
     * Return null in case of error
     * Returns true if payment is already ended or CB expired
     * Returns false otherwise
     *
     * @param $reason
     * @param $monthNumberSinceInitialPaymentDate
     * @return bool|null
     */
    public function isRecurringPaymentEndedOrExpired(&$reason,&$monthNumberSinceInitialPaymentDate)
    {
        if (
            !$this->details
            || !array_key_exists('vads_effective_creation_date', $this->details)
            || !array_key_exists('vads_expiry_year', $this->details)
            || !array_key_exists('vads_effective_creation_date', $this->details)
        ) {
            $reason = "Attribut détails vide ou clés absentes.";
            return null;
        }
        $firstDayOfCreationMonth = DateTime::createFromFormat(
            'Ymd',
            substr($this->details['vads_effective_creation_date'], 0, 6) . "01"
        );
        if (!$firstDayOfCreationMonth) {
            $reason = "Error parsing vads_effective_creation_date : " . $this->details['vads_effective_creation_date'];
            return null;
        }
        $day = $this->getRecurrenceMonthDay() ? $this->getRecurrenceMonthDay() - 1 : 0; //if not set assume first day of month (not a big deal anyway)
        $dateOfFirstOccurenceAfterInitialPayment = $firstDayOfCreationMonth->modify(
            "+" . $day . " days next month"
        );

        $paymentEndDate = $this->getRecurrenceMonthsCount() ?
            $dateOfFirstOccurenceAfterInitialPayment->modify(
                /* why minus 2 ?
                 * Imagine adherent selected 2 occurences on d/m/Y, then
                 * paymentEndDate should be d/m+1/Y,
                 * which is already $dateOfFirstOccurenceAfterInitialPayment
                 */
                "+" . ($this->getRecurrenceMonthsCount() - 2) . " months"
            )
            : null; //assume no end date if recurrenceMonthsCount not set

        //Compute most recent occurence number
        $effective_creation_date = DateTime::createFromFormat(
            'Ymd',
            substr($this->details['vads_effective_creation_date'], 0, 8),
        );
        if (!$effective_creation_date) {
            $reason = "Error parsing vads_effective_creation_date : " . $this->details['vads_effective_creation_date'];
            return null;
        }
        $effective_creation_date->setTime(0,0);
        $now = new DateTime();
        $now->setTime(0,0);
        $monthNumberSinceInitialPaymentDate = $effective_creation_date->diff($now)->m + 1;

        //Now check expiry date
        $paymentEndDateDueToExpiry = new DateTime();
        $paymentEndDateDueToExpiry->setDate($this->details['vads_expiry_year'], $this->details['vads_expiry_month'], $day + 1);

        $now = new DateTime();
        $recurrenceAmount = $this->recurrenceAmount / 100;
        if ($paymentEndDate && $paymentEndDate < $paymentEndDateDueToExpiry) {
            //Compare now with payment end date
            $reason = "Paiement récurrent en cours de " . $recurrenceAmount . "€ jusqu'à dernière échéance le " . $paymentEndDate->format('d/m/Y') . ".";
            return $now >= $paymentEndDate;
        } else {
            //Compare now with expiry date
            $reason = "Paiement récurrent en cours de " . $recurrenceAmount . "€ jusqu'à dernière échéance le " . $paymentEndDateDueToExpiry->format('d/m/Y') . " en raison de l'expiration du moyen de paiement.";
            return $now >= $paymentEndDateDueToExpiry;
        }
    }
}
