<?php

namespace AIPT\Api\AutomationJobs;

use AIPT\Api\AutomationJobs\Interfaces\JobLoggerInterface;
use AIPT\Api\AutomationJobs\Models\JobLog;

/**
 * Job Logger
 *
 * Handles logging for automation jobs
 * Following Single Responsibility Principle
 *
 * @since 2.3.0
 */
class JobLogger implements JobLoggerInterface {

    /**
     * WordPress database instance
     * @var \wpdb
     */
    private $wpdb;

    /**
     * Job logs table name
     * @var string
     */
    private $logs_table;

    /**
     * Constructor
     */
    public function __construct() {
        global $wpdb;
        $this->wpdb = $wpdb;
        $this->logs_table = $wpdb->prefix . 'aipt_job_logs';
    }

    /**
     * Log an info message
     *
     * @param int $job_id Job ID
     * @param string $message Log message
     * @param array $context Additional context data
     * @return bool Success status
     */
    public function info($job_id, $message, $context = []) {
        return $this->log(JobLog::info($job_id, $message, $context));
    }

    /**
     * Log a warning message
     *
     * @param int $job_id Job ID
     * @param string $message Log message
     * @param array $context Additional context data
     * @return bool Success status
     */
    public function warning($job_id, $message, $context = []) {
        return $this->log(JobLog::warning($job_id, $message, $context));
    }

    /**
     * Log an error message
     *
     * @param int $job_id Job ID
     * @param string $message Log message
     * @param array $context Additional context data
     * @return bool Success status
     */
    public function error($job_id, $message, $context = []) {
        return $this->log(JobLog::error($job_id, $message, $context));
    }

    /**
     * Log a debug message
     *
     * @param int $job_id Job ID
     * @param string $message Log message
     * @param array $context Additional context data
     * @return bool Success status
     */
    public function debug($job_id, $message, $context = []) {
        return $this->log(JobLog::debug($job_id, $message, $context));
    }

    /**
     * Log a message
     *
     * @param JobLog $log Log entry
     * @return bool Success status
     */
    private function log(JobLog $log) {

        $validation_errors = $log->validate();
        if (!empty($validation_errors)) {
            return false;
        }



        $data = $log->toArray();
        unset($data['id']); 


        if (!empty($data['context'])) {
            $data['context'] = $this->redact_context_string($data['context']);
        }



        $result = $this->wpdb->insert(
            $this->logs_table,
            $data,
            [
                '%d', 
                '%s', 
                '%s', 
                '%s', 
                '%s'  
            ]
        );

        return $result !== false;
    }

    /**
     * Get logs for a job
     *
     * @param int $job_id Job ID
     * @param array $filters Filters (level, type, limit, offset)
     * @return array Job logs
     */
    public function getJobLogs($job_id, $filters = []) {
        $where_conditions = ['job_id = %d'];
        $where_values = [$job_id];


        if (!empty($filters['level'])) {
            $where_conditions[] = 'level = %s';
            $where_values[] = $filters['level'];
        }


        if (!empty($filters['type'])) {
            $where_conditions[] = "context LIKE %s";

            $where_values[] = '%' . $this->wpdb->esc_like('"type":"' . sanitize_text_field((string)$filters['type']) . '"') . '%';
        }


        $query = "SELECT * FROM {$this->logs_table} WHERE " . implode(' AND ', $where_conditions);
        $query .= " ORDER BY created_at DESC";


        $limit = isset($filters['limit']) ? (int) $filters['limit'] : 50;
        $offset = isset($filters['offset']) ? (int) $filters['offset'] : 0;

        $query .= " LIMIT %d OFFSET %d";
        $where_values[] = $limit;
        $where_values[] = $offset;


        $results = $this->wpdb->get_results(
            $this->wpdb->prepare($query, $where_values),
            ARRAY_A
        );



        $logs = [];
        foreach ($results as $result) {
            $logs[] = new JobLog($result);
        }

        return $logs;
    }

    /**
     * Get logs by level
     *
     * @param int $job_id Job ID
     * @param string $level Log level
     * @param int $limit Maximum number of logs
     * @param int $offset Offset for pagination
     * @return array Job logs
     */
    public function getLogsByLevel($job_id, $level, $limit = 50, $offset = 0) {
        return $this->getJobLogs($job_id, [
            'level' => $level,
            'limit' => $limit,
            'offset' => $offset
        ]);
    }

    /**
     * Clear logs for a job
     *
     * @param int $job_id Job ID
     * @param string|null $level Optional level filter
     * @return bool Success status
     */
    public function clearJobLogs($job_id, $level = null) {
        $where = ['job_id' => $job_id];
        $where_format = ['%d'];

        if ($level !== null) {
            $where['level'] = $level;
            $where_format[] = '%s';
        }

        $result = $this->wpdb->delete(
            $this->logs_table,
            $where,
            $where_format
        );

        return $result !== false;
    }

    /**
     * Get log statistics for a job
     *
     * @param int $job_id Job ID
     * @return array Log statistics by level
     */
    public function getLogStatistics($job_id) {
        $query = "
            SELECT
                level,
                COUNT(*) as count
            FROM {$this->logs_table}
            WHERE job_id = %d
            GROUP BY level
        ";


        $results = $this->wpdb->get_results(
            $this->wpdb->prepare($query, $job_id),
            ARRAY_A
        );



        $statistics = [
            'info' => 0,
            'warning' => 0,
            'error' => 0,
            'debug' => 0,
            'total' => 0
        ];


        foreach ($results as $result) {
            $statistics[$result['level']] = (int) $result['count'];
            $statistics['total'] += (int) $result['count'];
        }

        return $statistics;
    }

    /**
     * Clean old logs
     *
     * @param int $days_to_keep Number of days to keep logs
     * @return int Number of logs deleted
     */
    public function cleanOldLogs($days_to_keep = 30) {
        $cutoff_date = gmdate('Y-m-d H:i:s', strtotime("-{$days_to_keep} days"));


        $result = $this->wpdb->query(
            $this->wpdb->prepare(
                "DELETE FROM {$this->logs_table} WHERE created_at < %s",
                $cutoff_date
            )
        );


        return $result !== false ? $result : 0;
    }

    /**
     * Get recent error logs across all jobs
     *
     * @param int $limit Maximum number of logs
     * @return array Recent error logs
     */
    public function getRecentErrors($limit = 20) {
        $query = "
            SELECT l.*, j.name as job_name
            FROM {$this->logs_table} l
            LEFT JOIN {$this->wpdb->prefix}aipt_automation_jobs j ON l.job_id = j.id
            WHERE l.level = 'error'
            ORDER BY l.created_at DESC
            LIMIT %d
        ";


        $results = $this->wpdb->get_results(
            $this->wpdb->prepare($query, $limit),
            ARRAY_A
        );


        $logs = [];
        foreach ($results as $result) {
            $log = new JobLog($result);
            $log->job_name = $result['job_name'] ?? 'Unknown Job';
            $logs[] = $log;
        }

        return $logs;
    }

    /**
     * Get log count for a job
     *
     * @param int $job_id Job ID
     * @param string|null $level Optional level filter
     * @return int Log count
     */
    public function getLogCount($job_id, $level = null) {
        $where_conditions = ['job_id = %d'];
        $where_values = [$job_id];

        if ($level !== null) {
            $where_conditions[] = 'level = %s';
            $where_values[] = $level;
        }

        $query = "SELECT COUNT(*) FROM {$this->logs_table} WHERE " . implode(' AND ', $where_conditions);


        return (int) $this->wpdb->get_var(
            $this->wpdb->prepare($query, $where_values)
        );

    }

    /**
     * Get recent logs across all jobs
     *
     * @param int $limit Number of logs to retrieve
     * @return array Recent log entries
     */
    public function getRecentLogs($limit = 50) {
        $query = "
            SELECT
                job_id,
                level,
                message,
                context,
                created_at
            FROM {$this->logs_table}
            ORDER BY created_at DESC
            LIMIT %d
        ";


        $results = $this->wpdb->get_results(
            $this->wpdb->prepare($query, $limit)
        );


        return $results ?: [];
    }

    /**
     * Redact sensitive information from JSON context string
     */
    private function redact_context_string($json) {
        $arr = json_decode($json, true);
        if (json_last_error() !== JSON_ERROR_NONE || !is_array($arr)) {
            return $json;
        }
        $redacted = $this->redact_array_recursive($arr);
        return wp_json_encode($redacted);
    }

    /**
     * Recursively redact sensitive keys in array
     */
    private function redact_array_recursive($data) {
        if (!is_array($data)) { return $data; }
        $sensitive_keys = ['api_key','apikey','authorization','token','secret','password','bearer','openai_api_key','openrouter_api_key','gemini_api_key'];
        foreach ($data as $k => $v) {
            if (is_array($v)) {
                $data[$k] = $this->redact_array_recursive($v);
                continue;
            }
            $lk = strtolower((string)$k);
            foreach ($sensitive_keys as $needle) {
                if (strpos($lk, $needle) !== false) {
                    $val = (string) $v;
                    if ($val === '') { $data[$k] = ''; break; }

                    $data[$k] = str_repeat('*', max(0, strlen($val) - 4)) . substr($val, -4);
                    break;
                }
            }
        }
        return $data;
    }

}
