<?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 EFlex
{
    public const STATE_DRAFT = 'draft';
    public const STATE_ACTIVE = 'active';
    public const STATE_COMPLETED = 'completed';
    public const STATE_CANCELLED = 'cancelled';
    public const STATE_PENDING_SETUP = 'pending_setup';

    public const METHOD_SEPA = 'sepa';
    public const METHOD_CB = 'cb';
    public const METHOD_VIREMENT = 'virement';

    #[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\Column(length: 500)]
    private string $description;

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

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

    #[ORM\Column(length: 20, options: ['default' => 'sepa'])]
    private string $paymentMethod = self::METHOD_SEPA;

    #[ORM\Column(length: 255, nullable: true)]
    private ?string $stripeCustomerId = 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: 'eflex_pdf', fileNameProperty: 'pdfUnsigned')]
    private ?File $pdfUnsignedFile = null;

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

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

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

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

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

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

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

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

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

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

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

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

        return $this;
    }

    public function getTotalAmount(): string
    {
        return $this->totalAmount;
    }

    public function setTotalAmount(string $totalAmount): static
    {
        $this->totalAmount = $totalAmount;

        return $this;
    }

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

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

        return $this;
    }

    public function getPaymentMethod(): string
    {
        return $this->paymentMethod;
    }

    public function setPaymentMethod(string $paymentMethod): static
    {
        $this->paymentMethod = $paymentMethod;

        return $this;
    }

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

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

        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;
    }

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

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

        return $this;
    }

    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;
    }

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

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

        return $this;
    }

    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 $pdfUnsignedFile): static
    {
        $this->pdfUnsignedFile = $pdfUnsignedFile;
        if (null !== $pdfUnsignedFile) {
            $this->updatedAt = new \DateTimeImmutable();
        }

        return $this;
    }

    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 $pdfSignedFile): static
    {
        $this->pdfSignedFile = $pdfSignedFile;
        if (null !== $pdfSignedFile) {
            $this->updatedAt = new \DateTimeImmutable();
        }

        return $this;
    }

    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 $pdfAuditFile): static
    {
        $this->pdfAuditFile = $pdfAuditFile;
        if (null !== $pdfAuditFile) {
            $this->updatedAt = new \DateTimeImmutable();
        }

        return $this;
    }

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

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

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

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

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

        return $count;
    }

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

        return $count;
    }

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

        return $total;
    }

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

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

    public function getPaymentMethodLabel(): string
    {
        return match ($this->paymentMethod) {
            self::METHOD_SEPA => 'Prelevement SEPA',
            self::METHOD_CB => 'Carte bancaire',
            self::METHOD_VIREMENT => 'Virement bancaire',
            default => $this->paymentMethod,
        };
    }
}
