<?php

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


// Detect if loaded by the user or by PHP
if (count(get_included_files()) == 1) {
    define("LOADED", true);
} else {
    define("LOADED", false);
}

require_once __DIR__ . "/../required.php";

use League\Csv\Writer;
use League\Csv\HTMLConverter;
use odsPhpGenerator\ods;
use odsPhpGenerator\odsTable;
use odsPhpGenerator\odsTableRow;
use odsPhpGenerator\odsTableColumn;
use odsPhpGenerator\odsTableCellString;
use odsPhpGenerator\odsStyleTableColumn;
use odsPhpGenerator\odsStyleTableCell;

require_once __DIR__ . "/userinfo.php";
require_once __DIR__ . "/login.php";

// Allow access with a download code, for mobile app and stuff
$date = date("Y-m-d H:i:s");
$allowed_users = [];
$requester = -1;
if (isset($VARS['code']) && LOADED) {
    if (!$database->has('report_access_codes', ["AND" => ['code' => $VARS['code'], 'expires[>]' => $date]])) {
        dieifnotloggedin();
        $requester = $_SESSION['uid'];
    } else {
        $requester = $database->get('report_access_codes', 'uid', ['code' => $VARS['code']]);
    }
} else {
    dieifnotloggedin();
    $requester = $_SESSION['uid'];
}

if (account_has_permission($_SESSION['username'], "ADMIN")) {
    $allowed_users = true;
} else {
    if (account_has_permission($_SESSION['username'], "QWIKCLOCK_MANAGE")) {
        $allowed_users = getManagedUIDs($requester);
    }

    if (account_has_permission($_SESSION['username'], "QWIKCLOCK_EDITSELF")) {
        $allowed_users[] = $_SESSION['uid'];
    }
}

// Delete old DB entries
$database->delete('report_access_codes', ['expires[<=]' => $date]);

if (LOADED) {
    $user = null;
    if (isset($VARS['type']) && isset($VARS['format'])) {
        generateReport($VARS['type'], $VARS['format'], $VARS['register'], $VARS['startdate'], $VARS['enddate']);
        die();
    } else {
        lang("invalid parameters");
        die();
    }
}

function getCashFlowReport($register = null, $start = null, $end = null) {
    global $database;
    $where = [];

    if (!is_null($register) && $database->has('registers', ['registerid' => $register])) {
        $where["registers.registerid"] = $register;
    }

    if ((bool) strtotime($start) == TRUE) {
        $where["OR #open"] = [
            "open[>=]" => date("Y-m-d", strtotime($start)),
            "close[>=]" => date("Y-m-d", strtotime($start))
        ];
    }
    if ((bool) strtotime($end) == TRUE) {
        // Make the date be the end of the day, not the start
        $where["close[<=]"] = date("Y-m-d", strtotime($end)) . " 23:59:59";
    }

    if (count($where) > 1) {
        $where = ["AND" => $where];
    }
    $cash = $database->select(
            "cash_drawer", [
        '[>]registers' => ['cash_drawer.registerid' => 'registerid'],
        '[>]transactions' => ['cash_drawer.cashid' => 'cashid'],
        '[>]payments' => ['transactions.txid' => 'txid'],
        '[>]payment_types' => ['payments.type' => 'typeid']
            ], [
        "cash_drawer.cashid",
        "registers.registername",
        "cash_drawer.registerid",
        "open",
        "close",
        "payments.type",
        "payments.amount",
        "payment_types.typename"
            ], $where
    );
    $header = [lang("register", false), lang("open", false), lang("close", false), lang("cash", false), lang("card", false), lang("check", false), lang("crypto", false), lang("gift card", false), lang("free", false)];
    $out = [$header];

    $registers = [];

    foreach ($cash as $c) {
        $registers[$c['registerid']]['name'] = $c['registername'];
        $registers[$c['registerid']]['id'] = $c['registerid'];
        $registers[$c['registerid']]['open'] = date(DATETIME_FORMAT, strtotime($c['open']));
        if (is_null($c['close'])) {
            $registers[$c['registerid']]['close'] = date(DATETIME_FORMAT);
        } else {
            $registers[$c['registerid']]['close'] = date(DATETIME_FORMAT, strtotime($c['close']));
        }
        if (!isset($registers[$c['registerid']][$c['typename']])) {
            $registers[$c['registerid']][$c['typename']] = 0.0;
        }
        $registers[$c['registerid']][$c['typename']] += $c['amount'];
    }

    foreach ($registers as $r) {
        $types = $database->select('payment_types', 'typename');
        foreach ($types as $t) {
            if (!isset($r[$t])) {
                $r[$t] = 0.0;
            }
        }
        $out[] = [
            $r['name'],
            $r['open'],
            $r['close'],
            $r['cash'] . "",
            $r['card'] . "",
            $r['check'] . "",
            $r['crypto'] . "",
            $r['giftcard'] . "",
            $r['free'] . ""
        ];
    }

    return $out;
}

function getReportData($type, $register = null, $start = null, $end = null) {
    switch ($type) {
        case "cashflow":
            return getCashFlowReport($register, $start, $end);
        default:
            return [["error"]];
    }
}

function dataToCSV($data, $name = "report", $register = null, $start = null, $end = null) {
    $csv = Writer::createFromString('');
    $usernotice = "";
    $usertitle = "";
    $datetitle = "";
    if ($start != null && (bool) strtotime($start)) {
        $datenotice = lang2("report filtered to start date", ["date" => date(DATE_FORMAT, strtotime($start))], false);
        $datetitle = "_" . date(DATE_FORMAT, strtotime($start));
        $csv->insertOne([$datenotice]);
    }
    if ($end != null && (bool) strtotime($end)) {
        $datenotice = lang2("report filtered to end date", ["date" => date(DATE_FORMAT, strtotime($end))], false);
        $datetitle .= ($datetitle == "" ? "_" : "-") . date(DATE_FORMAT, strtotime($end));
        $csv->insertOne([$datenotice]);
    }
    $csv->insertAll($data);
    header('Content-type: text/csv');
    header('Content-Disposition: attachment; filename="' . $name . $usertitle . $datetitle . "_" . date("Y-m-d_Hi") . ".csv" . '"');
    echo $csv;
    die();
}

function dataToODS($data, $name = "report", $register = null, $start = null, $end = null) {
    $ods = new ods();
    $styleColumn = new odsStyleTableColumn();
    $styleColumn->setUseOptimalColumnWidth(true);
    $headerstyle = new odsStyleTableCell();
    $headerstyle->setFontWeight("bold");
    $table = new odsTable($name);

    for ($i = 0; $i < count($data[0]); $i++) {
        $table->addTableColumn(new odsTableColumn($styleColumn));
    }

    $usernotice = "";
    $usertitle = "";
    $datetitle = "";
    if ($user != null && array_key_exists('username', $user) && array_key_exists('name', $user)) {
        $usernotice = lang2("report filtered to user", ["name" => $user['name'], "username" => $user['username']], false);
        $usertitle = "_" . $user['username'];
        $row = new odsTableRow();
        $row->addCell(new odsTableCellString($usernotice));
        $table->addRow($row);
    }
    if ($start != null && (bool) strtotime($start)) {
        $datenotice = lang2("report filtered to start date", ["date" => date(DATE_FORMAT, strtotime($start))], false);
        $datetitle = "_" . date(DATE_FORMAT, strtotime($start));
        $row = new odsTableRow();
        $row->addCell(new odsTableCellString($datenotice));
        $table->addRow($row);
    }
    if ($end != null && (bool) strtotime($end)) {
        $datenotice = lang2("report filtered to end date", ["date" => date(DATE_FORMAT, strtotime($end))], false);
        $datetitle .= ($datetitle == "" ? "_" : "-") . date(DATE_FORMAT, strtotime($end));
        $row = new odsTableRow();
        $row->addCell(new odsTableCellString($datenotice));
        $table->addRow($row);
    }

    $rowid = 0;
    foreach ($data as $datarow) {
        $row = new odsTableRow();
        foreach ($datarow as $cell) {
            if ($rowid == 0) {
                $row->addCell(new odsTableCellString($cell, $headerstyle));
            } else {
                $row->addCell(new odsTableCellString($cell));
            }
        }
        $table->addRow($row);
        $rowid++;
    }
    $ods->addTable($table);
    $ods->downloadOdsFile($name . $usertitle . $datetitle . "_" . date("Y-m-d_Hi") . ".ods");
}

function dataToHTML($data, $name = "report", $register = null, $start = null, $end = null) {
    global $SECURE_NONCE;
    // HTML exporter doesn't like null values
    for ($i = 0; $i < count($data); $i++) {
        for ($j = 0; $j < count($data[$i]); $j++) {
            if (is_null($data[$i][$j])) {
                $data[$i][$j] = '';
            }
        }
    }
    $datenotice = "";
    $datetitle = "";
    if ($start != null && (bool) strtotime($start)) {
        $datenotice = "<span>" . lang2("report filtered to start date", ["date" => date(DATE_FORMAT, strtotime($start))], false) . "</span><br />";
        $datetitle = "_" . date(DATE_FORMAT, strtotime($start));
    }
    if ($end != null && (bool) strtotime($end)) {
        $datenotice .= "<span>" . lang2("report filtered to end date", ["date" => date(DATE_FORMAT, strtotime($end))], false) . "</span><br />";
        $datetitle .= ($datetitle == "" ? "_" : "-") . date(DATE_FORMAT, strtotime($end));
    }
    header('Content-type: text/html');
    $converter = new HTMLConverter();
    $out = "<!DOCTYPE html>\n"
            . "<meta charset=\"utf-8\">\n"
            . "<meta name=\"viewport\" content=\"width=device-width\">\n"
            . "<title>" . $name . $datetitle . "_" . date("Y-m-d_Hi") . "</title>\n"
            . <<<STYLE
<style nonce="$SECURE_NONCE">
    .table-csv-data {
        border-collapse: collapse;
    }
    .table-csv-data tr:first-child {
        font-weight: bold;
    }
    .table-csv-data tr td {
        border: 1px solid black;
    }
</style>
STYLE
            . $datenotice
            . $converter->convert($data);
    echo $out;
}

function generateReport($type, $format, $register = null, $start = null, $end = null, $deleted = true) {
    $data = getReportData($type, $register, $start, $end, $deleted);
    switch ($format) {
        case "ods":
            dataToODS($data, $type, $register, $start, $end);
            break;
        case "html":
            dataToHTML($data, $type, $register, $start, $end);
            break;
        case "csv":
        default:
            echo dataToCSV($data, $type, $register, $start, $end);
            break;
    }
}
