<?php

namespace App\Entity\Model;

use App\Util\Inflector;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use function Symfony\Component\String\u;

/**
 * App\Entity\Model\Invoice
 *
 * @ORM\Table(indexes={
 *    @ORM\Index(name="invoice_cstnm_idx", columns={"customer_name"}),
 *    @ORM\Index(name="invoice_cstid_idx", columns={"customer_identification"}),
 *    @ORM\Index(name="invoice_cstml_idx", columns={"customer_email"}),
 *    @ORM\Index(name="invoice_cntct_idx", columns={"contact_person"})
 * })
 * @ORM\Entity(repositoryClass="App\Repository\InvoiceRepository")
 * @ORM\HasLifecycleCallbacks()
 */
class Invoice extends AbstractInvoice
{
    /**
     * @ORM\ManyToMany(targetEntity="Payment", orphanRemoval=true, cascade={"all"})
     * @ORM\JoinTable(name="invoices_payments",
     *      joinColumns={@ORM\JoinColumn(name="invoice_id", referencedColumnName="id", onDelete="CASCADE")},
     *      inverseJoinColumns={@ORM\JoinColumn(
     *          name="payment_id", referencedColumnName="id", unique=true, onDelete="CASCADE"
     *      )}
     * )
     */
    private $payments;

    /**
     * @var boolean $sent_by_email
     *
     * @ORM\Column(name="sent_by_email", type="boolean", nullable=true)
     */
    private $sent_by_email;

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

    /**
     * @var date $issue_date
     *
     * @ORM\Column(name="issue_date", type="date", nullable=true)
     * @Assert\Type("\DateTime")
     */
    private $issue_date;

    /**
     * @var date $due_date
     *
     * @ORM\Column(name="due_date", type="date", nullable=true)
     * @Assert\Type("\DateTime")
     */
    private $due_date;

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Model\Item", cascade={"all"}, inversedBy="invoice")
     * @ORM\JoinTable(name="invoices_items",
     *      joinColumns={@ORM\JoinColumn(name="invoice_id", referencedColumnName="id", onDelete="CASCADE")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="item_id", referencedColumnName="id", unique=true, onDelete="CASCADE")}
     * )
     * @Assert\NotBlank()
     */
    protected $items;

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Model\ItemPago", cascade={"all"}, inversedBy="invoices")
     * @ORM\JoinTable(name="invoices_pagos",
     *      joinColumns={@ORM\JoinColumn(name="invoice_id", referencedColumnName="id", onDelete="CASCADE")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="itempago_id", referencedColumnName="id", unique=true, onDelete="CASCADE")}
     * )
     * @Assert\NotBlank(allowNull=true)
     */
    protected $pagos;

    /**
     * @var boolean $closed
     *
     * @ORM\Column(name="closed", type="boolean", nullable=true)
     */
    private $forcefully_closed;

    /**
     * @var string $baseiva
     *
     * @ORM\Column(name="baseiva", type="decimal", scale=2, precision=15, nullable=true)
     */
    private $baseiva;

    /**
     * @var string $basecero
     *
     * @ORM\Column(name="basecero", type="decimal", scale=2, precision=15, nullable=true)
     */
    private $basecero;

    /**
     * @var string
     * @ORM\Column(name="claveacceso", type="string", length=49)
     */

    /**
     * @ORM\Column(name="base_iva5", type="decimal", scale=2, precision=18, nullable=true)
     */
    private $base_iva5;

    /**
     * @ORM\Column(name="base_iva8", type="decimal", scale=2, precision=18, nullable=true)
     */
    private $base_iva8;

    /**
     * @ORM\Column(name="base_ivacod6", type="decimal", scale=2, precision=18, nullable=true)
     */
    private $base_ivacod6;

    /**
     * @ORM\Column(name="base_ivacod7", type="decimal", scale=2, precision=18, nullable=true)
     */
    private $base_ivacod7;

    /**
     * @ORM\Column(name="valor_iva5", type="decimal", scale=2, precision=18, nullable=true)
     */
    private $valor_iva5;

    /**
     * @ORM\Column(name="valor_iva8", type="decimal", scale=2, precision=18, nullable=true)
     */
    private $valor_iva8;

    /**
     * @ORM\Column(name="valor_iva", type="decimal", scale=2, precision=18, nullable=true)
     */
    private $valor_iva;

    /**
     * @var string
     * @ORM\Column(name="claveacceso", type="string", length=49)
     */
    private $claveAcceso;

    /**
     * @var string
     * @ORM\Column(type="string", length=6)
     */
    private $serie;

    /**
     * @var
     *
     * @ORM\Column(type="decimal", scale=2, precision=15, nullable=true)
     */
    private $porIva;

    /**
     * @var text
     *
     * @ORM\Column(type="text", nullable=true)
     */
    private $xml;

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


    /**
     * @var boolean
     *
     * @ORM\Column( type="boolean")
     */
    private $autorizado;


    /**
     * @var string
     *
     * @ORM\Column(type="string", length=30,  nullable=true)
     */
    private $fecha_autorizacion;

    /**
     * @var boolean
     *
     * @ORM\Column( type="boolean")
     */
    private $sinrespuesta;

    /**
     * @var text
     *
     * @ORM\Column(type="text", nullable=true)
     */
    private $mensajeError;

    /**
     * @var text
     *
     * @ORM\Column(type="text", nullable=true)
     */
    private $xmlAutorizado;

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

    /**
     * @var boolean
     *
     * @ORM\Column( type="boolean")
     */
    private $anulado;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Model\Empresa")
     * @ORM\JoinColumn(name="empresa_id", referencedColumnName="id", onDelete="SET NULL")
     */
    private $empresa;

    private $totalFactura;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Model\TransporteSocio")
     * @ORM\JoinColumn(name="transportesocio_id", referencedColumnName="id", onDelete="SET NULL")
     */
    private $transportesocio;

    /**
     * @var string
     *
     * @ORM\Column(type="string", length=7,  nullable=true)
     */
    private $placa;
    
   /**
 * @ORM\Column(name="placa2", type="string", length=20, nullable=true)
 */
private $placa2;

/**
 * @ORM\Column(name="socio", type="string", length=150, nullable=true)
 */
private $socio;

    /*
    public function __construct()
    {
        parent::__construct();
        $this->payments = new ArrayCollection();
        $this->issue_date = new \DateTime();
        $this->due_date = new \DateTime();

        $this->porIva = 0.00;
        $this->claveAcceso = '';
        $this->serie = '';
        $this->autorizado = false;
        $this->sinrespuesta = false;
        $this->anulado = false;
    }
    
    */    
    
    
     public function __construct()
{
    parent::__construct();
    $this->payments = new ArrayCollection();

    $tz = new \DateTimeZone('America/Guayaquil');
    $this->issue_date = new \DateTime('now', $tz);
    $this->due_date = new \DateTime('now', $tz);

    $this->porIva = 0.00;
    $this->claveAcceso = '';
    $this->serie = '';
    $this->autorizado = false;
    $this->sinrespuesta = false;
    $this->anulado = false;
}



    /**
     * @return boolean
     */
    public function isClosed()
    {
        return $this->status === Invoice::CLOSED;
    }

    /**
     * @return boolean
     */
    public function isOpen()
    {
        return in_array($this->status, [Invoice::OPENED, Invoice::OVERDUE], true);
    }

    /**
     * @return boolean
     */
    public function isOverdue()
    {
        return $this->status === Invoice::OVERDUE;
    }

    /**
     * @return boolean
     */
    public function isDraft()
    {
        return $this->status === Invoice::DRAFT;
    }

    /**
     * Set sent_by_email
     *
     * @param boolean $sentByEmail
     */
    public function setSentByEmail($sentByEmail)
    {
        $this->sent_by_email = $sentByEmail;
    }

    /**
     * Get sent_by_email
     *
     * @return boolean
     */
    public function isSentByEmail(): bool
    {
        return (bool)$this->sent_by_email;
    }

    /**
     * Set number
     *
     * @param integer $number
     */
    public function setNumber($number)
    {
        $this->number = $number;
    }

    /**
     * Get number
     *
     * @return integer
     */
    public function getNumber()
    {

        return $this->number;
    }

    /**
     * Set issue_date
     *
     * @param date $issueDate
     */
    public function setIssueDate($issueDate)
    {
        $this->issue_date = $issueDate instanceof \DateTime ?
            $issueDate : new \DateTime($issueDate);
    }

    /**
     * Get issue_date
     *
     * @return date
     */
    public function getIssueDate()
    {
        return $this->issue_date;
    }

    /**
     * Set due_date
     *
     * @param date $dueDate
     */
    public function setDueDate($dueDate)
    {
        $this->due_date = $dueDate instanceof \DateTime ?
            $dueDate : new \DateTime($dueDate);
    }

    /**
     * Get due_date
     *
     * @return date
     */
    public function getDueDate()
    {
        return $this->due_date;
    }

    /**
     * Add payments
     *
     * @param App\Entity\Model\Payment $payment
     */
    public function addPayment(\App\Entity\Model\Payment $payment)
    {
        $this->payments[] = $payment;
    }

    /**
     * Removes a payment.
     *
     * @param App\Entity\Model\Payment $payment
     */
    public function removePayment(\App\Entity\Model\Payment $payment)
    {
        foreach ($this->getPayments() as $key => $value) {
            if ($value === $payment) {
                unset($this->payments[$key]);
                break;
            }
        }
    }

    /**
     * Get payments
     *
     * @return Doctrine\Common\Collections\Collection
     */
    public function getPayments()
    {
        return $this->payments;
    }

    public function setForcefullyClosed($value)
    {
        $this->forcefully_closed = $value;
    }

    public function isForcefullyClosed()
    {
        return $this->forcefully_closed;
    }

    /** **************** CUSTOM METHODS AND PROPERTIES **************  */

    /**
     * TODO: provide the serie .
     */
    public function __toString()
    {
        return $this->label();
    }

    public function label(string $draftLabel = '[draft]')
    {
        /*$series = $this->getSeries();
        $label = '';
        $label .= $series ? $series->getValue() : '';
        $label .= $this->isDraft() ? $draftLabel : $this->getNumber();
*/

        $label = sprintf("%09d", $this->getNumber());
        return $label;
    }

    public function labelPdf()
    {
        $label = sprintf("FA-%06d-%09d.pdf",$this->getSerie(),$this->getNumber());
        return $label;
    }

    public function labelNumDocSustento(string $draftLabel = '[draft]')
    {
        $label = sprintf("%09d", $this->numeroDocSustento);
        return $label;
    }

    const DRAFT = 0;
    const CLOSED = 1;
    const OPENED = 2;
    const OVERDUE = 3;

    public function getDueAmount()
    {
        if ($this->isDraft()) {
            return null;
        }
        return $this->getGrossAmount() - $this->getPaidAmount();
    }

    /**
     * try to catch custom methods to be used in twig templates
     */
    public function __get($name)
    {
        if (strpos($name, 'tax_amount_') === 0) {
            return $this->calculate($name, true);
        }
        //$method = Inflector::camelize("get_{$name}");
        $method = 'get'.u($name)->camel()->title()->toString();
        if (method_exists($this, $method)) {
            return $this->$method();
        }
        return false;
    }

    public function __isset($name)
    {
        if (strpos($name, 'tax_amount_') === 0) {
            return true;
        }

        if (in_array($name, ['due_amount'])) {
            return true;
        }

        if (in_array($name, array_keys(get_object_vars($this)))) {
            return true;
        }

        return parent::__isset($name);
    }

    public function getStatusString()
    {
        switch ($this->status) {
            case Invoice::DRAFT;
                $status = 'draft';
                break;
            case Invoice::CLOSED;
                $status = 'closed';
                break;
            case Invoice::OPENED;
                $status = 'opened';
                break;
            case Invoice::OVERDUE:
                $status = 'overdue';
                break;
            default:
                $status = 'unknown';
                break;
        }
        return $status;
    }

    /**
     * checkStatus
     * checks and sets the status
     *
     * @return App\Invoice $this
     */
    public function checkStatus()
    {
        if ($this->status == Invoice::DRAFT) {
            return $this;
        }

        if ($this->isForcefullyClosed() || $this->getDueAmount() <= 0) {
            $this->setStatus(Invoice::CLOSED);
        } else {
            if ($this->getDueDate()->getTimestamp() > strtotime(date('Y-m-d'))) {
                $this->setStatus(Invoice::OPENED);
            } else {
                $this->setStatus(Invoice::OVERDUE);
            }
        }

        return $this;
    }

    public function checkAmounts()
    {
        parent::checkAmounts();
        $this->setPaidAmount($this->calculate('paid_amount'));

        return $this;
    }

    public function checkNumber(LifecycleEventArgs $args)
    {
        // compute the number of invoice
        if ((!$this->number && $this->status != self::DRAFT) ||
            ($args instanceof PreUpdateEventArgs && $args->hasChangedField('series') && $this->status != self::DRAFT)
        ) {
            $repo = $args->getEntityManager()->getRepository('App\Entity\Model\Invoice');
            $series = $this->getSeries();
            if ($repo && $series)
            {
                $resp = $repo->getNextNumber($series, $this->getEmpresa()->getId());
                $this->setNumber($resp);
            }
        }
    }

    /* ********** LIFECYCLE CALLBACKS *********** */

    /**
     * @ORM\PrePersist
     * @ORM\PreUpdate
     */
    public function preSave(LifecycleEventArgs $args)
    {
        $this->setUpdatedAt(new \DateTime('now'));

        if ($this->getCreatedAt() == null) {
            $this->setCreatedAt(new \DateTime('now'));
        }

        $this->checkAmounts();
        parent::presave($args);

        $this->checkNumber($args);

    }

    /**
     * @return string
     */
    public function getCustomermicro()
    {
        return $this->customermicro;
    }

    /**
     * @param string $customermicro
     */
    public function setCustomermicro(string $customermicro)
    {
        $this->customermicro = $customermicro;
    }

    /**
     * @return decimal
     */
    public function getBaseiva()
    {
        return $this->baseiva;
    }

    /**
     * @param decimal $baseiva
     */
    public function setBaseiva($baseiva)
    {
        $this->baseiva = $baseiva;
    }

    /**
     * @return decimal
     */
    public function getBasecero()
    {
        return $this->basecero;
    }

    /**
     * @param decimal $basecero
     */
    public function setBasecero($basecero)
    {
        $this->basecero = $basecero;
    }

    /**
     * @return mixed
     */
    public function getPorIva()
    {
        return $this->porIva;
    }

    /**
     * @param mixed $porIva
     */
    public function setPorIva($porIva)
    {
        $this->porIva = $porIva;
    }

    /**
     * @return string
     */
    public function getClaveAcceso()
    {
        return $this->claveAcceso;
    }

    /**
     * @param string $claveAcceso
     */
    public function setClaveAcceso($claveAcceso)
    {
        $this->claveAcceso = $claveAcceso;
    }

    /**
     * @return string
     */
    public function getSerie()
    {
        return $this->serie;
    }

    /**
     * @param string $serie
     */
    public function setSerie($serie)
    {
        $this->serie = $serie;
    }

    /**
     * @return bool
     */
    public function getAutorizado()
    {
        return $this->autorizado;
    }

    /**
     * @param bool $autorizado
     */
    public function setAutorizado($autorizado)
    {
        $this->autorizado = $autorizado;
    }

    /**
     * @return string
     */
    public function getAutorizacion()
    {
        return $this->autorizacion;
    }

    /**
     * @param string $autorizacion
     */
    public function setAutorizacion($autorizacion)
    {
        $this->autorizacion = $autorizacion;
    }


    /**
     * @return text
     */
    public function getXml()
    {
        return $this->xml;
    }

    /**
     * @param text $xml
     */
    public function setXml($xml)
    {
        $this->xml = $xml;
    }

    /**
     * @return mixed
     */
    public function getEmpresa()
    {
        return $this->empresa;
    }

    /**
     * @param mixed $empresa
     */
    public function setEmpresa($empresa)
    {
        $this->empresa = $empresa;
    }

    /**
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getPagos()
    {
        return $this->pagos;
    }

    /**
     * @param mixed $pagos
     */
    public function setPagos($pagos)
    {
        $this->pagos = $pagos;
    }

    /**
     * @return string
     */
    public function getFechaAutorizacion()
    {
        return $this->fecha_autorizacion;
    }

    /**
     * @param string $fecha_autorizacion
     */
    public function setFechaAutorizacion(string $fecha_autorizacion)
    {
        $this->fecha_autorizacion = $fecha_autorizacion;
    }

    /**
     * @return int
     */
    public function getAmbiente()
    {
        return $this->ambiente;
    }

    /**
     * @param int $ambiente
     */
    public function setAmbiente($ambiente)
    {
        $this->ambiente = $ambiente;
    }

    /**
     * @param mixed $ambiente
     */
    public function getLabelAmbiente()
    {
        if ($this->ambiente === 1)
            return "PRUEBAS";
        else if ($this->ambiente === 2)
            return "PRODUCCION";
        else
            return "UNDEFINED";

    }

    /**
     * @return bool
     */
    public function isSinrespuesta()
    {
        return $this->sinrespuesta;
    }

    /**
     * @param bool $sinrespuesta
     */
    public function setSinrespuesta($sinrespuesta)
    {
        $this->sinrespuesta = $sinrespuesta;
    }

    /**
     * @return text
     */
    public function getMensajeError()
    {
        return $this->mensajeError;
    }

    /**
     * @param text $mensajeError
     */
    public function setMensajeError($mensajeError)
    {
        $this->mensajeError = $mensajeError;
    }

    /**
     * @return text
     */
    public function getXmlAutorizado()
    {
        return $this->xmlAutorizado;
    }

    /**
     * @param text $xmlAutorizado
     */
    public function setXmlAutorizado($xmlAutorizado)
    {
        $this->xmlAutorizado = $xmlAutorizado;
    }

    /**
     * @return mixed
     */
    public function getDocpdf()
    {
        return $this->docpdf;
    }

    /**
     * @param mixed $docpdf
     */
    public function setDocpdf($docpdf)
    {
        $this->docpdf = $docpdf;
    }

    /**
     * @return bool
     */
    public function getAnulado(): bool
    {
        return $this->anulado;
    }

    /**
     * @param bool $anulado
     */
    public function setAnulado(bool $anulado): void
    {
        $this->anulado = $anulado;
    }

    /**
     * @return string
     */
    public function getEstado(): string
    {
        if ($this->autorizado)
            return 'A';
        else
            return 'N';
    }

    /**
     * @return mixed
     */
    public function getTotalFactura()
    {
        return round($this->totalFactura,2);
    }

    /**
     * @param mixed $totalFactura
     */
    public function setTotalFactura($totalFactura): void
    {
        $this->totalFactura = $totalFactura;
    }

    /**
     * @return mixed
     */
    public function getTransportesocio()
    {
        return $this->transportesocio;
    }

    /**
     * @param mixed $transportesocio
     */
    public function setTransportesocio($transportesocio)
    {
        $this->transportesocio = $transportesocio;
    }

    /**
     * @return string
     */
    public function getPlaca()
    {
        return $this->placa;
    }

    /**
     * @param string $placa
     */
    public function setPlaca($placa)
    {
        $this->placa = $placa;
    }
    
    
   

public function getPlaca2()
{
    return $this->placa2;
}

public function setPlaca2($placa2)
{
    $this->placa2 = $placa2;

    return $this;
}

public function getSocio()
{
    return $this->socio;
}

public function setSocio($socio)
{
    $this->socio = $socio;

    return $this;
}



    /**
     * @return mixed
     */
    public function getBaseIva5()
    {
        return $this->base_iva5;
    }

    /**
     * @param mixed $base_iva5
     */
    public function setBaseIva5($base_iva5)
    {
        $this->base_iva5 = $base_iva5;
    }

    /**
     * @return mixed
     */
    public function getBaseIva8()
    {
        return $this->base_iva8;
    }

    /**
     * @param mixed $base_iva8
     */
    public function setBaseIva8($base_iva8)
    {
        $this->base_iva8 = $base_iva8;
    }

    /**
     * @return mixed
     */
    public function getBaseIvacod6()
    {
        return $this->base_ivacod6;
    }

    /**
     * @param mixed $base_ivacod6
     */
    public function setBaseIvacod6($base_ivacod6)
    {
        $this->base_ivacod6 = $base_ivacod6;
    }

    /**
     * @return mixed
     */
    public function getBaseIvacod7()
    {
        return $this->base_ivacod7;
    }

    /**
     * @param mixed $base_ivacod7
     */
    public function setBaseIvacod7($base_ivacod7)
    {
        $this->base_ivacod7 = $base_ivacod7;
    }

    /**
     * @return mixed
     */
    public function getValorIva5()
    {
        return $this->valor_iva5;
    }

    /**
     * @param mixed $valor_iva5
     */
    public function setValorIva5($valor_iva5)
    {
        $this->valor_iva5 = $valor_iva5;
    }

    /**
     * @return mixed
     */
    public function getValorIva8()
    {
        return $this->valor_iva8;
    }

    /**
     * @param mixed $valor_iva8
     */
    public function setValorIva8($valor_iva8)
    {
        $this->valor_iva8 = $valor_iva8;
    }

    /**
     * @return mixed
     */
    public function getValorIva()
    {
        return $this->valor_iva;
    }

    /**
     * @param mixed $valor_iva
     */
    public function setValorIva($valor_iva)
    {
        $this->valor_iva = $valor_iva;
    }


}
