<?php

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

class LogModerationController extends BaseController
{
    public function index()
    {
        $this->checkScopes(['admin.view']);
        $rawParams = $this->request->get();
        $rawParams['limit'] = $this->getDefaultLimit($rawParams);
        $rawParams['offset'] = array_key_exists('offset', $rawParams) ? $rawParams['offset'] : 0;
        $rawParams['order_by'] = array_key_exists('order_by', $rawParams) ? $rawParams['order_by'] : 'moderated_at';
        $rawParams['order_direction'] = array_key_exists('order_direction', $rawParams) ? $rawParams['order_direction'] : 'desc';

        $validatedParams = $this->validate($rawParams, [
            'limit' => ['validators' => [
                'required', 'digit', ['name' => 'max', 'params' => 1000]
            ]],
            'offset' => ['validators' => [
                'required', 'digit'
            ]],
            'action' => ['validators' => [
                [
                    'name' => 'inclusion_in',
                    'params' => array_merge([null], array_keys(LogModeration::ACTION_LABEL))
                ]
            ]],
            'ref_id' => ['validators' => [
                'digit'
            ]],
            'moderated_by' => ['validators' => [
                'digit'
            ]],
            'moderated_at_from' => ['validators' => [
                'date'
            ]],
            'moderated_at_to' => ['validators' => [
                'date'
            ]],
            'order_by' => ['validators' => [
                [
                    'name' => 'inclusion_in',
                    'params' => ['moderated_at', 'moderated_by', 'action']
                ]
            ]],
            'order_direction' => ['validators' => [
                [
                    'name' => 'inclusion_in',
                    'params' => ['asc', 'desc']
                ]
            ]]
        ]);

        $query = [
            'conditions' => 'action ILIKE :action:',
            'bind' => [
                'action' => '%' . $validatedParams['action'] . '%'
            ]
        ];
        $conditions = "action ILIKE :action";

        if ($validatedParams['action'] === LogModeration::ACTION_BAN_UMUSER) {
            $query['conditions'] .= " AND action NOT ILIKE '" . LogModeration::ACTION_UNBAN_UMUSER . "'";
            $conditions .= " AND action NOT ILIKE '" . LogModeration::ACTION_UNBAN_UMUSER . "'";
        }

        if (!is_null($validatedParams['ref_id'])) {
            $query['conditions'] .= " AND ref_id = :ref_id:";
            $conditions .= " AND ref_id = :ref_id";
            $query['bind']['ref_id'] = $validatedParams['ref_id'];
        }

        if (!is_null($validatedParams['moderated_by'])) {
            $query['conditions'] .= " AND moderated_by = :moderated_by:";
            $conditions .= " AND moderated_by = :moderated_by";
            $query['bind']['moderated_by'] = $validatedParams['moderated_by'];
        }

        if (!is_null($validatedParams['moderated_at_from'])) {
            $query['conditions'] .= " AND cast(moderated_at as date) >= :moderated_at_from:";
            $conditions .= " AND cast(moderated_at as date) >= :moderated_at_from";
            $query['bind']['moderated_at_from'] = $validatedParams['moderated_at_from'];
        }

        if (!is_null($validatedParams['moderated_at_to'])) {
            $query['conditions'] .= " AND cast(moderated_at as date) <= :moderated_at_to:";
            $conditions .= " AND cast(moderated_at as date) <= :moderated_at_to";
            $query['bind']['moderated_at_to'] = $validatedParams['moderated_at_to'];
        }

        $total = LogModeration::count($query);
        $query['bind']['limit'] = $validatedParams['limit'];
        $query['bind']['offset'] = $validatedParams['offset'];
        $rows = $this->rawQuery("
            SELECT
                log_moderation.*,
                u1.um_user_name as moderated_username,
                (
                    CASE
                        WHEN log_moderation.ref_table = 'um_user' THEN u2.um_user_name
                    END
                ) as ref_name
            FROM
                log_moderation
            LEFT JOIN
                um_user u1 ON u1.um_id = log_moderation.moderated_by
            LEFT OUTER JOIN
                um_user u2 ON (u2.um_id = log_moderation.ref_id AND log_moderation.ref_table = 'um_user')
            WHERE " . $conditions . "
            ORDER BY " . $validatedParams['order_by'] . " " . $validatedParams['order_direction'] . "
            LIMIT :limit OFFSET :offset
                ;
        ", $query['bind']);

        return new PaginatedResponse($rows, $total, $query['bind']['limit'], $query['bind']['offset']);
    }

    public function detail($id)
    {
        $this->checkScopes(['admin.view']);
        /** @var LogModeration $row */
        $row = LogModeration::findFirst($id);
        if (!$row) {
            throw new CustomErrorException(BaseResponse::DATA_NOT_FOUND, "Data tidak ditemukan");
        }
        $data = $row->toArray();
        $data['data_from'] = json_decode($row->data_from);
        $data['data_to'] = json_decode($row->data_to);
        $data['moderated_username'] = $row->moderator->um_user_name;

        return new SimpleResponse($data);
    }

    public function actionReference()
    {
        $this->checkScopes(['admin.view']);

        return new SimpleResponse(LogModeration::ACTION_LABEL);
    }

    public function export()
    {
        $this->checkScopes(['admin.view']);
        $rawParams = $this->request->get();
        $rawParams['order_by'] = array_key_exists('order_by', $rawParams) ? $rawParams['order_by'] : 'moderated_at';
        $rawParams['order_direction'] = array_key_exists('order_direction', $rawParams) ? $rawParams['order_direction'] : 'desc';

        $validatedParams = $this->validate($rawParams, [
            'action' => ['validators' => [
                [
                    'name' => 'inclusion_in',
                    'params' => array_merge([null], array_keys(LogModeration::ACTION_LABEL))
                ]
            ]],
            'ref_id' => ['validators' => [
                'digit'
            ]],
            'moderated_by' => ['validators' => [
                'digit'
            ]],
            'moderated_at_from' => ['validators' => [
                'date'
            ]],
            'moderated_at_to' => ['validators' => [
                'date'
            ]],
            'order_by' => ['validators' => [
                [
                    'name' => 'inclusion_in',
                    'params' => ['moderated_at', 'moderated_by', 'action']
                ]
            ]],
            'order_direction' => ['validators' => [
                [
                    'name' => 'inclusion_in',
                    'params' => ['asc', 'desc']
                ]
            ]]
        ]);

        $query = [
            'conditions' => 'action ILIKE :action:',
            'bind' => [
                'action' => '%' . $validatedParams['action'] . '%'
            ]
        ];
        $conditions = "action ILIKE :action";

        if ($validatedParams['action'] === LogModeration::ACTION_BAN_UMUSER) {
            $query['conditions'] .= " AND action NOT ILIKE '" . LogModeration::ACTION_UNBAN_UMUSER . "'";
            $conditions .= " AND action NOT ILIKE '" . LogModeration::ACTION_UNBAN_UMUSER . "'";
        }

        if (!is_null($validatedParams['ref_id'])) {
            $query['conditions'] .= " AND ref_id = :ref_id:";
            $conditions .= " AND ref_id = :ref_id";
            $query['bind']['ref_id'] = $validatedParams['ref_id'];
        }

        if (!is_null($validatedParams['moderated_by'])) {
            $query['conditions'] .= " AND moderated_by = :moderated_by:";
            $conditions .= " AND moderated_by = :moderated_by";
            $query['bind']['moderated_by'] = $validatedParams['moderated_by'];
        }

        if (!is_null($validatedParams['moderated_at_from'])) {
            $query['conditions'] .= " AND cast(moderated_at as date) >= :moderated_at_from:";
            $conditions .= " AND cast(moderated_at as date) >= :moderated_at_from";
            $query['bind']['moderated_at_from'] = $validatedParams['moderated_at_from'];
        }

        if (!is_null($validatedParams['moderated_at_to'])) {
            $query['conditions'] .= " AND cast(moderated_at as date) <= :moderated_at_to:";
            $conditions .= " AND cast(moderated_at as date) <= :moderated_at_to";
            $query['bind']['moderated_at_to'] = $validatedParams['moderated_at_to'];
        }
        $data = $this->rawQuery("
            SELECT
                log_moderation.*,
                u1.um_user_name as moderated_username,
                (
                    CASE
                        WHEN log_moderation.ref_table = 'um_user' THEN u2.um_user_name
                    END
                ) as ref_name
            FROM
                log_moderation
            LEFT JOIN
                um_user u1 ON u1.um_id = log_moderation.moderated_by
            LEFT OUTER JOIN
                um_user u2 ON (u2.um_id = log_moderation.ref_id AND log_moderation.ref_table = 'um_user')
            WHERE " . $conditions . "
            ORDER BY " . $validatedParams['order_by'] . " " . $validatedParams['order_direction'] . "
                ;
        ", $query['bind']);

        $lastCol = "H";
        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();

        $sheet->setCellValue("A1", 'No');
        $sheet->setCellValue("B1", 'Akun');
        $sheet->setCellValue("C1", 'Aksi');
        $sheet->setCellValue("D1", 'Oleh');
        $sheet->setCellValue("E1", 'Menu');
        $sheet->setCellValue("F1", 'Tanggal');
        $sheet->setCellValue("G1", 'Data Sebelum');
        $sheet->setCellValue("H1", 'Data Sesudah');
        $sheet->getStyle("A1:".$lastCol."1")->getFont()->setBold(true);
        $sheet->getStyle("A1:".$lastCol."1")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);

        $row = 1;
        $num = 1;

        foreach ($data as $datum) {
            $row++;
            $sheet->setCellValue("A$row", $num);
            $sheet->setCellValue("B$row", $datum["ref_name"]);
            $sheet->setCellValue("C$row", $datum["action"]);
            $sheet->setCellValue("D$row", $datum["moderated_username"]);
            $sheet->setCellValue("E$row", $datum["action_menu"]);
            $sheet->setCellValue("F$row", $datum["moderated_at"]);
            $sheet->setCellValue("G$row", $datum["data_from"]);
            $sheet->setCellValue("H$row", $datum["data_to"]);
            $num++;
        }

        $styleArray = [
            'borders' => [
                'allBorders' => [
                    'borderStyle' => Border::BORDER_THIN,
                    'color' => ['argb' => 'FF000000'],
                ],
            ],
        ];
        $sheet->getStyle('A1:'. $lastCol . ($row))->applyFromArray($styleArray);

        $writer = new Xlsx($spreadsheet);
        $filename = "Log Moderation - " . DateHelper::formatTodayIndex() . ".xlsx";
        header('Content-type: application/vnd.ms-excel');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        return $writer->save('php://output');
    }

    /**
     * @return SimpleResponse
     * @throws CustomErrorException
     * Testing purpose only
     */
    public function seed() {
        $this->checkScopes(['admin.view']);

        $adminUserIds = Roles::getAdminUserIds();
        $refUserIds = UmUser::find(['columns' => 'um_id'])->toArray();

        $i=0;
        while($i<1000) {
            $selectedAdminId = $adminUserIds[array_rand($adminUserIds)];
            $selectedRefId = $refUserIds[array_rand($refUserIds)]["um_id"];
            $actions = $this->randFromArray(array_keys(LogModeration::ACTION_LABEL), 2);
            $actionMenu = implode(" ", $this->randFromArray([LogModeration::ACTIONMENU_ADMINISTRASI_PANCEK, LogModeration::ACTIONMENU_ADMINISTRASI_MONITORING, LogModeration::ACTIONMENU_ADMINISTRASI_PAK, LogModeration::ACTIONMENU_ADMINISTRASI_KORWIL, LogModeration::ACTIONMENU_ADMINISTRASI_JAGA], 1));
            $dataFrom = LogModeration::extractUmUser($selectedRefId);
            $dataTo = $dataFrom;

            if (in_array(LogModeration::ACTION_BAN_UMUSER, $actions) && !in_array(LogModeration::ACTION_UNBAN_UMUSER, $actions)) {
                $dataFrom['is_banned'] = false;
                $dataTo['is_banned'] = true;
            }
            if (!in_array(LogModeration::ACTION_BAN_UMUSER, $actions) && in_array(LogModeration::ACTION_UNBAN_UMUSER, $actions)) {
                $dataFrom['is_banned'] = true;
                $dataTo['is_banned'] = false;
            }
            if (in_array(LogModeration::ACTION_UPDATE_UMUSER, $actions)) {
                $dataFrom['nama'] .= " Edited";
            }

            LogModeration::loggedUmUser(
                $actions,
                $actionMenu,
                $selectedRefId,
                $dataFrom,
                $dataTo,
                $selectedAdminId
            );
            $i++;
        }

        return new SimpleResponse(LogModeration::findFirst(['order' => 'id desc']));
    }

    private function randFromArray(Array $array, $maxLength) {
        $s = array_rand($array, rand(1,$maxLength));
        if (!is_array($s)) $s = [$s];
        $res = [];
        foreach ($s as $i) {
            array_push($res, $array[$i]);
        }

        return $res;
    }
}
