<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Attribute as Vich;

#[ORM\Entity]
#[Vich\Uploadable]
class Echeancier
{
    public const STATE_DRAFT = 'draft';
    public const STATE_SEND = 'send';
    public const STATE_SIGNED = 'signed';
    public const STATE_ACTIVE = 'active';
    public const STATE_COMPLETED = 'completed';
    public const STATE_CANCELLED = 'cancelled';
    public const STATE_DEFAULT = 'default';
    public const STATE_PENDING_SETUP = 'pending_setup';

    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\ManyToOne(targetEntity: Customer::class)]
    #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
    private Customer $customer;

    #[ORM\ManyToOne(targetEntity: Advert::class)]
    #[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
    private ?Advert $advert = null;

    #[ORM\Column(length: 500)]
    private string $description;

    #[ORM\Column(type: 'decimal', precision: 10, scale: 2)]
    private string $totalAmountHt;

    #[ORM\Column(length: 20, options: ['default' => 'draft'])]
    private string $state = self::STATE_DRAFT;

    #[ORM\Column(nullable: true)]
    private ?int $submitterCompanyId = null;

    #[ORM\Column(nullable: true)]
    private ?int $submitterCustomerId = null;

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

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

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

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

    #[ORM\Column(length: 4, nullable: true)]
    private ?string $stripeSepaLast4 = null;

    #[ORM\Column(length: 100, nullable: true)]
    private ?string $stripeSepaBankName = null;

    #[ORM\Column(length: 2, nullable: true)]
    private ?string $stripeSepaCountry = null;

    #[ORM\Column(nullable: true)]
    private ?string $submissionId = null;

    // ── PDF Unsigned ──
    #[ORM\Column(length: 255, nullable: true)]
    private ?string $pdfUnsigned = null;

    #[Vich\UploadableField(mapping: 'echeancier_pdf', fileNameProperty: 'pdfUnsigned')]
    private ?File $pdfUnsignedFile = null;

    // ── PDF Signed ──
    #[ORM\Column(length: 255, nullable: true)]
    private ?string $pdfSigned = null;

    #[Vich\UploadableField(mapping: 'echeancier_signed_pdf', fileNameProperty: 'pdfSigned')]
    private ?File $pdfSignedFile = null;

    // ── PDF Audit ──
    #[ORM\Column(length: 255, nullable: true)]
    private ?string $pdfAudit = null;

    #[Vich\UploadableField(mapping: 'echeancier_audit_pdf', fileNameProperty: 'pdfAudit')]
    private ?File $pdfAuditFile = null;

    #[ORM\Column]
    private \DateTimeImmutable $createdAt;

    #[ORM\Column(nullable: true)]
    private ?\DateTimeImmutable $updatedAt = null;

    /** @var Collection<int, EcheancierLine> */
    #[ORM\OneToMany(targetEntity: EcheancierLine::class, mappedBy: 'echeancier', cascade: ['persist', 'remove'], orphanRemoval: true)]
    #[ORM\OrderBy(['scheduledAt' => 'ASC'])]
    private Collection $lines;

    public function __construct(Customer $customer, string $description, string $totalAmountHt)
    {
        $this->customer = $customer;
        $this->description = $description;
        $this->totalAmountHt = $totalAmountHt;
        $this->createdAt = new \DateTimeImmutable();
        $this->lines = new ArrayCollection();
    }

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

    public function getCustomer(): Customer
    {
        return $this->customer;
    }

    public function getAdvert(): ?Advert
    {
        return $this->advert;
    }

    public function setAdvert(?Advert $advert): static
    {
        $this->advert = $advert;

        return $this;
    }

    public function getDescription(): string
    {
        return $this->description;
    }

    public function setDescription(string $description): static
    {
        $this->description = $description;

        return $this;
    }

    public function getTotalAmountHt(): string
    {
        return $this->totalAmountHt;
    }

    public function setTotalAmountHt(string $totalAmountHt): static
    {
        $this->totalAmountHt = $totalAmountHt;

        return $this;
    }

    public function getState(): string
    {
        return $this->state;
    }

    public function setState(string $state): static
    {
        $this->state = $state;
        $this->updatedAt = new \DateTimeImmutable();

        return $this;
    }

    public function getSubmitterCompanyId(): ?int
    {
        return $this->submitterCompanyId;
    }

    public function setSubmitterCompanyId(?int $submitterCompanyId): static
    {
        $this->submitterCompanyId = $submitterCompanyId;

        return $this;
    }

    public function getSubmitterCustomerId(): ?int
    {
        return $this->submitterCustomerId;
    }

    public function setSubmitterCustomerId(?int $submitterCustomerId): static
    {
        $this->submitterCustomerId = $submitterCustomerId;

        return $this;
    }

    public function getStripeSubscriptionId(): ?string
    {
        return $this->stripeSubscriptionId;
    }

    public function setStripeSubscriptionId(?string $stripeSubscriptionId): static
    {
        $this->stripeSubscriptionId = $stripeSubscriptionId;

        return $this;
    }

    public function getStripeCustomerId(): ?string
    {
        return $this->stripeCustomerId;
    }

    public function setStripeCustomerId(?string $stripeCustomerId): static
    {
        $this->stripeCustomerId = $stripeCustomerId;

        return $this;
    }

    public function getStripePriceId(): ?string
    {
        return $this->stripePriceId;
    }

    public function setStripePriceId(?string $stripePriceId): static
    {
        $this->stripePriceId = $stripePriceId;

        return $this;
    }

    public function getStripePaymentMethodId(): ?string
    {
        return $this->stripePaymentMethodId;
    }

    public function setStripePaymentMethodId(?string $stripePaymentMethodId): static
    {
        $this->stripePaymentMethodId = $stripePaymentMethodId;

        return $this;
    }

    public function getStripeSepaLast4(): ?string
    {
        return $this->stripeSepaLast4;
    }

    public function setStripeSepaLast4(?string $stripeSepaLast4): static
    {
        $this->stripeSepaLast4 = $stripeSepaLast4;

        return $this;
    }

    public function getStripeSepaBankName(): ?string
    {
        return $this->stripeSepaBankName;
    }

    public function setStripeSepaBankName(?string $stripeSepaBankName): static
    {
        $this->stripeSepaBankName = $stripeSepaBankName;

        return $this;
    }

    public function getStripeSepaCountry(): ?string
    {
        return $this->stripeSepaCountry;
    }

    public function setStripeSepaCountry(?string $stripeSepaCountry): static
    {
        $this->stripeSepaCountry = $stripeSepaCountry;

        return $this;
    }

    public function getSubmissionId(): ?string
    {
        return $this->submissionId;
    }

    public function setSubmissionId(?string $submissionId): static
    {
        $this->submissionId = $submissionId;

        return $this;
    }

    // ── PDF Unsigned ──

    public function getPdfUnsigned(): ?string
    {
        return $this->pdfUnsigned;
    }

    public function setPdfUnsigned(?string $pdfUnsigned): static
    {
        $this->pdfUnsigned = $pdfUnsigned;

        return $this;
    }

    public function getPdfUnsignedFile(): ?File
    {
        return $this->pdfUnsignedFile;
    }

    public function setPdfUnsignedFile(?File $file): void
    {
        $this->pdfUnsignedFile = $file;
        if (null !== $file) {
            $this->updatedAt = new \DateTimeImmutable();
        }
    }

    // ── PDF Signed ──

    public function getPdfSigned(): ?string
    {
        return $this->pdfSigned;
    }

    public function setPdfSigned(?string $pdfSigned): static
    {
        $this->pdfSigned = $pdfSigned;

        return $this;
    }

    public function getPdfSignedFile(): ?File
    {
        return $this->pdfSignedFile;
    }

    public function setPdfSignedFile(?File $file): void
    {
        $this->pdfSignedFile = $file;
        if (null !== $file) {
            $this->updatedAt = new \DateTimeImmutable();
        }
    }

    // ── PDF Audit ──

    public function getPdfAudit(): ?string
    {
        return $this->pdfAudit;
    }

    public function setPdfAudit(?string $pdfAudit): static
    {
        $this->pdfAudit = $pdfAudit;

        return $this;
    }

    public function getPdfAuditFile(): ?File
    {
        return $this->pdfAuditFile;
    }

    public function setPdfAuditFile(?File $file): void
    {
        $this->pdfAuditFile = $file;
        if (null !== $file) {
            $this->updatedAt = new \DateTimeImmutable();
        }
    }

    // ── Dates ──

    public function getCreatedAt(): \DateTimeImmutable
    {
        return $this->createdAt;
    }

    public function getUpdatedAt(): ?\DateTimeImmutable
    {
        return $this->updatedAt;
    }

    public function setUpdatedAt(?\DateTimeImmutable $updatedAt): static
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    // ── Lines ──

    /** @return Collection<int, EcheancierLine> */
    public function getLines(): Collection
    {
        return $this->lines;
    }

    public function addLine(EcheancierLine $line): static
    {
        if (!$this->lines->contains($line)) {
            $this->lines->add($line);
        }

        return $this;
    }

    public function removeLine(EcheancierLine $line): static
    {
        $this->lines->removeElement($line);

        return $this;
    }

    public const MAJORATION_RATE = 0.05;

    // ── Computed ──

    /**
     * Montant de la majoration (5% du montant total).
     */
    public function getMajoration(): float
    {
        return round((float) $this->totalAmountHt * self::MAJORATION_RATE, 2);
    }

    /**
     * Montant total avec majoration (total + 5%).
     */
    public function getTotalWithMajoration(): float
    {
        return round((float) $this->totalAmountHt + $this->getMajoration(), 2);
    }

    public function getNbLines(): int
    {
        return $this->lines->count();
    }

    public function getNbPaid(): int
    {
        $count = 0;
        foreach ($this->lines as $line) {
            if (EcheancierLine::STATE_OK === $line->getState()) {
                ++$count;
            }
        }

        return $count;
    }

    public function getNbFailed(): int
    {
        $count = 0;
        foreach ($this->lines as $line) {
            if (EcheancierLine::STATE_KO === $line->getState()) {
                ++$count;
            }
        }

        return $count;
    }

    public function getTotalPaid(): float
    {
        $total = 0.0;
        foreach ($this->lines as $line) {
            if (EcheancierLine::STATE_OK === $line->getState()) {
                $total += (float) $line->getAmount();
            }
        }

        return $total;
    }

    public function getProgress(): float
    {
        $nb = $this->getNbLines();

        return $nb > 0 ? round($this->getNbPaid() / $nb * 100, 1) : 0.0;
    }

    /**
     * Montant mensuel (total majore / nb echeances).
     */
    public function getMonthlyAmount(): float
    {
        $nb = $this->getNbLines();

        return $nb > 0 ? round($this->getTotalWithMajoration() / $nb, 2) : 0.0;
    }

    /**
     * Reference unique de l'echeancier (EC_ECH_00001).
     */
    public function getReference(): string
    {
        return 'EC_ECH_'.str_pad((string) ($this->id ?? 0), 5, '0', \STR_PAD_LEFT);
    }
}
