<?php

use Symfony\Component\Yaml\Yaml;

require_once APPPATH . 'libraries/Cf_REST_Controller.php';
require_once APPPATH . 'models/Entities/CF_AuditLogListArguments.php';

class AuditlogAPI extends Cf_REST_Controller
{
    public function __construct()
    {
        parent::__construct();
        $this->load->model('auditlog_model');
    }

    public function logs_get()
    {
        $arguments = CF_AuditLogListArguments::fromArray($_REQUEST);
        $apiResponse = $this->auditlog_model->list($arguments);
        $logs = AuditlogsTransformer::transform($apiResponse['data']);
        $json = json_encode($logs);
        respond_ok($json, total: $apiResponse['meta']['total']);
    }

    public function log_get($id)
    {
        $apiResponse = $this->auditlog_model->item((int) $id);
        $logs = AuditlogsTransformer::transform([$apiResponse]);
        $json = json_encode($logs[0]);
        respond_ok($json);
    }

    public function names_get($type)
    {
        respond_ok(json_encode($this->auditlog_model->namesByType($type)));
    }

    public function actors_get()
    {
        respond_ok(json_encode($this->auditlog_model->actors()));
    }

    public function logs_export_get()
    {
        header('Content-Type: text/csv');
        header('Content-Disposition: attachment');

        $arguments = CF_AuditLogListArguments::fromArray($_REQUEST);
        $apiResponse = $this->auditlog_model->list($arguments);
        $logs = AuditlogsTransformer::transform($apiResponse['data']);
        $headers = ['Timestamp', 'Performed by', 'Action', 'Type', 'Affected', 'Details'];
        $output = fopen('php://output', 'w');

        fputcsv($output, $headers);
        foreach ($logs as $log) {
            fputcsv($output, [
                $log['time'],
                $log['actor']['id'],
                $log['action'],
                $log['object']['type'],
                $log['object']['name'] ?? $log['object']['id'],
                Yaml::dump($log['change'], inline: 10, indent: 2) ?? '',
            ]);
        }

        fclose($output);
        exit();
    }
}

/**
 * Transform data to Mender API format
 */
class AuditlogsTransformer
{
    public static function transform(array $auditlogs): array
    {
        return array_map(function ($log) {
            return [
                'id' => $log['id'] ?? null,
                'action' => $log['action'] ?? null,
                'time' => $log['time'] ?? null,
                'actor' => self::transformActor($log['actor'] ?? null),
                'object' => self::transformObject($log),
                'change' => $log['details'] ?? null,
            ];
        }, $auditlogs);
    }

    private static function transformActor(?string $actor): array
    {
        return [
            'id' => $actor,
            'type' => 'user',
            'username' => $actor,
        ];
    }

    private static function transformObject(array $log): array
    {
        $objectId = $log['object_id'] ?? null;
        $objectType = $log['object_type'] ?? null;
        $objectName = $log['object_name'] ?? null;

        return [
            'id' => $objectId,
            'type' => $objectType,
            'name' => $objectName,
            $objectType => [
                'id' => $objectId,
            ],
        ];
    }

    private static function transformChange($details): string
    {
        if (!is_array($details)) {
            return '';
        }

        return trim(
            array_reduce(
                $details,
                function ($acc, $detail) {
                    if (is_string($detail)) {
                        $acc .= $detail . PHP_EOL;
                    } elseif (is_array($detail)) {
                        $acc .= json_encode($detail);
                    }
                    return $acc;
                },
                '',
            ),
        );
    }
}
