<?php

namespace App\Controllers;

use App\Models\ActivityLogModel;
use App\Models\UserModel;
use Config\Lookups;

/**
 * Manager-only. Phase 4's filterable-by-module/user/date/action audit
 * trail — the `module` column (written from day one) and every
 * logActivity() call site's "verb-first" sentence (see
 * ActivityLogModel::actionTag()) make this possible without
 * back-filling any data. ?user_id= (added alongside the Staff Profile
 * page's Activity Log tab and "View Activity Log" quick action)
 * predates this and still works the same way, now alongside the fuller
 * filter set.
 */
class ActivityLogController extends BaseController
{
    public function index()
    {
        $model = new ActivityLogModel();

        [$builder, $filters] = $this->filteredBuilder($model);

        $perPage = (int) ($this->request->getGet('per_page') ?: 10);
        $perPage = in_array($perPage, [10, 25, 50], true) ? $perPage : 10;

        $entries = $builder->orderBy('activity_log.created_at', 'desc')->paginate($perPage);

        return view('activity_log/index', [
            'pageTitle'  => 'Activity Log',
            'entries'    => $entries,
            'pager'      => $model->pager,
            'perPage'    => $perPage,
            'filters'    => $filters,
            'filterUser' => $filters['user_id'] > 0 ? (new UserModel())->find($filters['user_id']) : null,
            'stats'      => $this->stats(),
            'users'      => (new UserModel())->orderBy('full_name')->findAll(),
            'modules'    => $this->moduleOptions(),
            'actionTags' => $model->distinctActionTags(),
        ]);
    }

    /** Same filtered query as index(), minus pagination — kept in sync so the CSV never disagrees with what's on screen. */
    public function exportCsv()
    {
        $model = new ActivityLogModel();
        [$builder] = $this->filteredBuilder($model);

        $rows = $builder->orderBy('activity_log.created_at', 'desc')->findAll();

        $csv = fopen('php://temp', 'w+');
        fputcsv($csv, ['MaxYields Activity Log']);
        fputcsv($csv, []);
        fputcsv($csv, ['Date & Time', 'User', 'Module', 'Action', 'Details', 'IP Address']);

        foreach ($rows as $row) {
            fputcsv($csv, [
                $row->created_at,
                $row->user_name ?? 'System',
                $row->module,
                ActivityLogModel::actionTag($row->action, $row->user_name),
                $row->action,
                $row->ip_address ?? '',
            ]);
        }

        rewind($csv);
        $contents = stream_get_contents($csv);
        fclose($csv);

        $this->logActivity('activity_log', 'Exported activity log CSV (' . count($rows) . ' rows).');

        return $this->response
            ->setHeader('Content-Type', 'text/csv')
            ->setHeader('Content-Disposition', 'attachment; filename="activity-log-' . date('Y-m-d') . '.csv"')
            ->setBody($contents);
    }

    /**
     * @return array{0: \App\Models\ActivityLogModel, 1: array} The
     *              filtered query builder plus the resolved filter
     *              values (also handed back to the view to re-populate
     *              the filter form).
     */
    private function filteredBuilder(ActivityLogModel $model): array
    {
        $filters = [
            'date_from' => $this->request->getGet('date_from') ?: '',
            'date_to'   => $this->request->getGet('date_to') ?: '',
            'user_id'   => (int) $this->request->getGet('user_id'),
            'module'    => $this->request->getGet('module') ?: '',
            'action'    => $this->request->getGet('action') ?: '',
        ];

        $builder = $model
            ->select('activity_log.*, users.full_name as user_name')
            ->join('users', 'users.id = activity_log.user_id', 'left');

        if ($filters['date_from'] !== '') {
            $builder->where('activity_log.created_at >=', $filters['date_from'] . ' 00:00:00');
        }

        if ($filters['date_to'] !== '') {
            $builder->where('activity_log.created_at <=', $filters['date_to'] . ' 23:59:59');
        }

        if ($filters['user_id'] > 0) {
            $builder->where('activity_log.user_id', $filters['user_id']);
        }

        if ($filters['module'] !== '') {
            $builder->where('activity_log.module', $filters['module']);
        }

        if ($filters['action'] !== '') {
            // Contains, not starts-with — most tags are the sentence's own
            // leading word, but a few 'auth' rows have the verb appear
            // after the actor's name instead (see ActivityLogModel::
            // actionTag()'s doc comment), so a strict prefix match would
            // silently return nothing for those.
            $builder->like('activity_log.action', $filters['action']);
        }

        return [$builder, $filters];
    }

    /**
     * Always the tenant-wide totals regardless of the filter row (same
     * convention as every other redesigned list page's KPI cards this
     * session) — Today/This Week/This Month/All Time activity counts.
     */
    private function stats(): array
    {
        // A fresh model instance per query — CI4's query builder is
        // cached on the model instance, so reusing/cloning one risks
        // where() clauses bleeding between these counts.
        return [
            'today'      => (new ActivityLogModel())->where('created_at >=', date('Y-m-d') . ' 00:00:00')->countAllResults(),
            'this_week'  => (new ActivityLogModel())->where('created_at >=', date('Y-m-d', strtotime('monday this week')) . ' 00:00:00')->countAllResults(),
            'this_month' => (new ActivityLogModel())->where('created_at >=', date('Y-m-01') . ' 00:00:00')->countAllResults(),
            'all_time'   => (new ActivityLogModel())->countAllResults(),
        ];
    }

    /** Real distinct module values present in the data, labeled via Lookups::$permissionModules where a matching key exists. */
    private function moduleOptions(): array
    {
        $labels = (new Lookups())->permissionModules;
        $rows   = (new ActivityLogModel())->distinct()->select('module')->orderBy('module')->findAll();

        $options = [];

        foreach ($rows as $row) {
            $options[$row->module] = $labels[$row->module]['label'] ?? ucfirst(str_replace('_', ' ', $row->module));
        }

        return $options;
    }
}
