<?php
/*
 * OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
 * Copyright (C) DevCode s.r.l.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */

include_once __DIR__.'/../../core.php';

use Modules\Anagrafiche\Anagrafica;
use Modules\Articoli\Articolo as ArticoloOriginale;
use Modules\Emails\Mail;
use Modules\Emails\Template;
use Modules\Fatture\Components\Descrizione;
use Modules\Fatture\Components\Riga;
use Modules\Fatture\Fattura;
use Modules\Interventi\Components\Sessione;
use Modules\Interventi\Intervento;
use Modules\Interventi\Components\Riga as RigaIntervento;
use Util\Generator;
use Util\Ini;

/**
 * Recupera il totale delle ore spese per un intervento.
 *
 * @param int $id_intervento
 *
 * @deprecated
 */
function get_ore_intervento($id_intervento)
{
    $intervento = Intervento::find($id_intervento);

    return $intervento->ore_totali;
}

/**
 * Funzione per collegare gli articoli, usati in un intervento, ai rispettivi impianti.
 *
 * @param int $id_intervento
 * @param int $id_impianto
 * @param int $id_articolo
 * @param int $qta
 *
 * @deprecated 2.4.25
 */
function link_componente_to_articolo($id_intervento, $id_impianto, $id_articolo, $qta)
{
    if (empty($id_impianto) || empty($id_intervento)) {
        return;
    }

    $dbo = database();
    $intervento = Intervento::find($id_intervento);

    // Data di inizio dell'intervento (data_richiesta in caso di assenza di sessioni)
    $data = $intervento->inizio ?: $intervento->data_richiesta;

    // Se l'articolo aggiunto è collegato a un componente, aggiungo il componente all'impianto selezionato
    $componente_articolo = $dbo->fetchOne('SELECT componente_filename, contenuto FROM mg_articoli WHERE id = '.prepare($id_articolo));
    if (!empty($componente_articolo) && !empty($componente_articolo['componente_filename'])) {
        $contenuto_ini = Ini::read($componente_articolo['contenuto']);
        $nome_componente = Ini::getValue($contenuto_ini, 'Nome');

        $dati = [
            'idimpianto' => $id_impianto,
            'idintervento' => $id_intervento,
            'nome' => $nome_componente,
            'data' => $data,
            'filename' => $componente_articolo['componente_filename'],
            'contenuto' => $componente_articolo['contenuto'],
        ];

        // Inserisco il componente tante volte quante la quantità degli articoli inseriti
        for ($q = 0; $q < $qta; ++$q) {
            $dbo->insert('my_impianto_componenti', $dati);
        }
    }
}

function add_tecnico($id_intervento, $idtecnico, $inizio, $fine, $idcontratto = null)
{
    $intervento = Intervento::find($id_intervento);
    $anagrafica = Anagrafica::find($idtecnico);

    $sessione = Sessione::build($intervento, $anagrafica, $inizio, $fine);

    // Notifica nuovo intervento al tecnico
    if (setting('Notifica al tecnico l\'aggiunta della sessione nell\'attività')) {
        if (!empty($anagrafica['email'])) {
            $template = Template::pool('Notifica intervento');

            if (!empty($template)) {
                $mail = Mail::build(auth()->getUser(), $template, $id_intervento);
                $mail->addReceiver($anagrafica['email']);
                $mail->save();
            }
        }
    }

    //Inserisco le righe aggiuntive previste dal tipo di intervento
    $righe_aggiuntive = database()->fetchArray("SELECT * FROM in_righe_tipiinterventi WHERE id_tipointervento=".prepare($sessione->idtipointervento));

    foreach($righe_aggiuntive as $riga_aggiuntiva){
        $riga = RigaIntervento::build($intervento);

        $riga->descrizione = $riga_aggiuntiva['descrizione'];
        $riga->um = $riga_aggiuntiva['um'];

        $riga->costo_unitario = $riga_aggiuntiva['prezzo_acquisto'];
        $riga->setPrezzoUnitario( $riga_aggiuntiva['prezzo_vendita'], $riga_aggiuntiva['idiva'] );
        $riga->qta = $riga_aggiuntiva['qta'];

        $riga->save();
    }

    return true;
}

/**
 * Calcola le ore presenti tra due date.
 *
 * @param string $orario_inizio
 * @param string $orario_fine
 *
 * @return float
 *
 * @deprecated
 */
function calcola_ore_intervento($orario_inizio, $orario_fine)
{
    $inizio = new DateTime($orario_inizio);
    $diff = $inizio->diff(new DateTime($orario_fine));

    $ore = $diff->i / 60 + $diff->h + ($diff->days * 24);

    return $ore;
}

function aggiungi_intervento_in_fattura($id_intervento, $id_fattura, $descrizione, $id_iva, $id_conto, $id_rivalsa_inps = false, $id_ritenuta_acconto = false, $calcolo_ritenuta_acconto = false)
{
    $dbo = database();

    $id_rivalsa_inps = $id_rivalsa_inps !== false ? $id_rivalsa_inps : setting('Cassa previdenziale predefinita');
    $id_ritenuta_acconto = $id_ritenuta_acconto !== false ? $id_ritenuta_acconto : setting("Ritenuta d'acconto predefinita");
    $calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto !== false ? $calcolo_ritenuta_acconto : setting("Metodologia calcolo ritenuta d'acconto predefinito");

    $fattura = Fattura::find($id_fattura);
    $intervento = Intervento::find($id_intervento);

    $data = $intervento->fine;
    $codice = $intervento->codice;

    // Riga di descrizione
    $riga = Descrizione::build($fattura);
    $riga->descrizione = $descrizione;
    $riga->idintervento = $id_intervento;
    $riga->save();

    // Ore di lavoro raggruppate per costo orario
    $sessioni = $intervento->sessioni;

    if (empty($sessioni)) {
        flash()->warning(tr("L'attività _NUM_ non ha sessioni di lavoro!", [
            '_NUM_' => $codice,
        ]));
    } else {
        $decimals = setting('Cifre decimali per quantità');

        $ore_di_lavoro = $sessioni->groupBy(function ($item, $key) {
            return $item['prezzo_orario'].'|'.$item['sconto_unitario'].'|'.$item['tipo_sconto'];
        });
        foreach ($ore_di_lavoro as $gruppo) {
            $sessione = $gruppo->first();
            $riga = Riga::build($fattura);

            $riga->descrizione = tr("Ore di lavoro dell'attività _NUM_ del _DATE_", [
                '_NUM_' => $codice,
                '_DATE_' => dateFormat($data),
            ]);
            $riga->idintervento = $id_intervento;
            $riga->um = 'ore';

            $riga->id_iva = $id_iva;
            $riga->idconto = $id_conto;

            $riga->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto;
            $riga->id_ritenuta_acconto = $id_ritenuta_acconto;
            $riga->id_rivalsa_inps = $id_rivalsa_inps;

            $riga->prezzo_unitario = $sessione->prezzo_orario;

            //Calcolo lo sconto unitario della sessione in base all'impostazione sui prezzi ivati
            $iva = $dbo->table('co_iva')->where('id', $id_iva)->first();
            if ($sessione->tipo_sconto == 'UNT' && setting('Utilizza prezzi di vendita comprensivi di IVA')) {
                $sconto_unitario = $sessione->sconto_unitario + (($sessione->sconto_unitario * $iva->percentuale) / 100);
            } else {
                $sconto_unitario = $sessione->sconto_unitario;
            }

            $riga->setSconto($sconto_unitario, $sessione->tipo_sconto);

            $qta_gruppo = $gruppo->sum('ore');
            $riga->qta = round($qta_gruppo, $decimals);

            // Riferimento al documento di origine
            $riga->original_document_type = get_class($intervento);
            $riga->original_document_id = $intervento->id;

            $riga->save();
        }

        // Diritti di chiamata raggruppati per costo
        $diritti_chiamata = $sessioni->where('prezzo_diritto_chiamata', '>', 0)->groupBy(function ($item, $key) {
            return $item['prezzo_diritto_chiamata'];
        });
        foreach ($diritti_chiamata as $gruppo) {
            $diritto_chiamata = $gruppo->first();
            $riga = Riga::build($fattura);

            $riga->descrizione = tr("Diritto di chiamata dell'attività _NUM_ del _DATE_", [
                '_NUM_' => $codice,
                '_DATE_' => dateFormat($data),
            ]);
            $riga->idintervento = $id_intervento;
            //$riga->um = 'ore';

            $riga->id_iva = $id_iva;
            $riga->idconto = $id_conto;

            $riga->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto;
            $riga->id_ritenuta_acconto = $id_ritenuta_acconto;
            $riga->id_rivalsa_inps = $id_rivalsa_inps;

            $riga->prezzo_unitario = $diritto_chiamata->prezzo_diritto_chiamata;

            $riga->qta = $gruppo->count();

            // Riferimento al documento di origine
            $riga->original_document_type = get_class($intervento);
            $riga->original_document_id = $intervento->id;

            $riga->save();
        }

        // Viaggi raggruppati per costo
        $viaggi = $sessioni->where('prezzo_km_unitario', '>', 0)->groupBy(function ($item, $key) {
            return $item['prezzo_km_unitario'].'|'.$item['scontokm_unitario'].'|'.$item['tipo_scontokm'];
        });
        foreach ($viaggi as $gruppo) {
            $qta_trasferta = $gruppo->sum('km');
            if ($qta_trasferta == 0) {
                continue;
            }

            $viaggio = $gruppo->first();
            $riga = Riga::build($fattura);

            $riga->descrizione = tr("Trasferta dell'attività _NUM_ del _DATE_", [
                '_NUM_' => $codice,
                '_DATE_' => dateFormat($data),
            ]);
            $riga->idintervento = $id_intervento;
            $riga->um = 'km';

            $riga->id_iva = $id_iva;
            $riga->idconto = $id_conto;

            $riga->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto;
            $riga->id_ritenuta_acconto = $id_ritenuta_acconto;
            $riga->id_rivalsa_inps = $id_rivalsa_inps;

            $riga->prezzo_unitario = $viaggio->prezzo_km_unitario;
            $riga->setSconto($viaggio->scontokm_unitario, $viaggio->tipo_scontokm);

            // Riferimento al documento di origine
            $riga->original_document_type = get_class($intervento);
            $riga->original_document_id = $intervento->id;

            $riga->qta = $qta_trasferta;

            $riga->save();
        }
    }

    // Articoli, righe, sconti e descrizioni collegati all'intervento
    $righe = $intervento->getRighe();
    foreach ($righe as $riga) {
        $qta = $riga->qta;
        $copia = $riga->copiaIn($fattura, $qta);

        $copia->id_conto = $id_conto;

        $copia->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto;
        $copia->id_ritenuta_acconto = $id_ritenuta_acconto;
        $copia->id_rivalsa_inps = $id_rivalsa_inps;

        // Aggiornamento seriali dalla riga dell'ordine
        if ($copia->isArticolo()) {
            $copia->serials = $riga->serials;
            $articolo = ArticoloOriginale::find($copia->idarticolo);
            $copia->id_conto = ($articolo->idconto_vendita ? $articolo->idconto_vendita : $id_conto);
        }

        $copia->save();
    }

    // Ricalcolo inps, ritenuta e bollo
    ricalcola_costiagg_fattura($id_fattura);

    // Metto l'intervento in stato "Fatturato"
    $dbo->query("UPDATE in_interventi SET idstatointervento=(SELECT idstatointervento FROM in_statiintervento WHERE codice='FAT') WHERE id=".prepare($id_intervento));
}

/**
 * Verifica che il numero_esterno della fattura indicata sia correttamente impostato, a partire dai valori delle fatture ai giorni precedenti.
 * Restituisce il numero_esterno mancante in caso di numero errato.
 *
 * @return bool|string
 */
function verifica_numero_intervento(Intervento $intervento)
{
    if (empty($intervento->codice)) {
        return null;
    }

    $data = $intervento->data_richiesta;
    $documenti = Intervento::whereDate('data_richiesta', '=', $data->format('Y-m-d'))
        ->get();

    // Recupero maschera per questo segmento
    $maschera = setting('Formato codice attività');

    if ((strpos($maschera, 'YYYY') == false) or (strpos($maschera, 'yy') == false)) {
        $ultimo = Generator::getPreviousFrom($maschera, 'in_interventi', 'codice', [
            'DATE(data_richiesta) < '.prepare($data->format('Y-m-d')),
            'YEAR(data_richiesta) = '.prepare($data->format('Y')),
        ], $data);
    } else {
        $ultimo = Generator::getPreviousFrom($maschera, 'in_interventi', 'codice', [
            'DATE(data_richiesta) < '.prepare($data->format('Y-m-d')),
        ]);
    }

    do {
        $numero = Generator::generate($maschera, $ultimo, 1, Generator::dateToPattern($data), $data);

        $filtered = $documenti->reject(function ($item, $key) use ($numero) {
            return $item->codice == $numero;
        });

        if ($documenti->count() == $filtered->count()) {
            return $numero;
        }

        $documenti = $filtered;
        $ultimo = $numero;
    } while ($numero != $intervento->codice);

    return null;
}