<?php

namespace RtmMail\Helpers;

/**
 * LogHelper - Logs model handles every database related sequence
 */
class LogHelper
{
    /**
     * TABLE_NAME - name of the database table
     * @type string
     */
    const TABLE_NAME = 'logs';
    /**
     * DEFAULT_ARGS - default settings to use for getting all logs
     * @type array
     */
    const DEFAULT_ARGS = [
        'orderby' => 'id',
        'order' => 'DESC',
        'post_per_page' => 10,
        'paged' => 1,
        's' => null,
        'where' => null,
        'date' => null,
    ];

    /**
     * get - Get database data based on given $args
     * @param array $args
     */
    public static function get($args = [], $isCount = false)
    {
        global $wpdb;

        // Merge the default args and the given args
        $args = array_merge(self::DEFAULT_ARGS, $args);

        if (!$isCount) {
            $query = "SELECT * FROM " . RTM_MAIL_TABLE_PREFIX . self::TABLE_NAME . " ";
        } else {
            $query = "SELECT COUNT(*) FROM " . RTM_MAIL_TABLE_PREFIX . self::TABLE_NAME . " ";
        }
        $where_added = false;

        // Check if a 'where' arg is given
        if ($args['where'] != null) {
            $query .= "WHERE ";
            // Loop through every 'where' value
            // Example: $args['where'] = [ 'example_column' => [ 'value' => 'example_value', 'type' => 'LIKE' ] ]; == WHERE example_column LIKE '%example_value%'
            foreach ($args['where'] as $column_name => $column_data) {
                // Escape the given value
                $column_value = esc_sql($column_data['value']);
                if ($column_data['type'] == 'LIKE') {
                    // Add percentages if the type is LIKE
                    $column_value = '%' . $column_value . '%';
                }
                // Check if it is the first key, if not add a which (AND/OR) to the query
                reset($args['where']);
                if ($column_name === key($args['where'])) {
                    $query .= $column_name . " " . $column_data['type'] . " '" . $column_value . "' ";
                } else {
                    // Quick check if an AND/OR is given, if not just add AND
                    $which = $column_data['which'] ?? 'AND';
                    $query .= $which . " " . $column_name . " " . $column_data['type'] . " '" . $column_value . "' ";
                }
            }
            $where_added = true;
        }

        // Check for a given search string
        if ($args['s'] != null && (isset($args['search_filter']) && !empty($args['search_filter']))) {
            // Check if there is already a where added if not add WHERE to the query
            if ($where_added) {
                $query .= "AND ";
            } else {
                $query .= "WHERE ";
                $where_added = true;
            }
            //Trim the search string
            $args['s'] = trim($args['s']);
            // Escape the search string
            $args['s'] = esc_sql($args['s']);
            // Loop through all the filtered rows
            foreach ($args['search_filter'] as $filter_column => $is_filter) {
                $filter_column = esc_sql($filter_column);
                // Search by the selected filter column
                if (filter_var($is_filter, FILTER_VALIDATE_BOOLEAN)) {
                    $query .= "(" . $filter_column . " LIKE '%" . $args['s'] . "%') OR ";
                }
                // Check for last in array (remove OR at the end)
                end($args['search_filter']);
                if ($filter_column === key($args['search_filter'])) {
                    $query .= "(" . $filter_column . " LIKE '%" . $args['s'] . "%') ";
                }
            }
        }

        if ($args['date'] != null) {
            $args['date_type'] = $args['date_type'] ?? 'created';
            if ($where_added) {
                $query .= "AND ";
            } else {
                $query .= "WHERE ";
            }
            $dates = explode(' - ', sanitize_text_field(wp_unslash($args['date'])));
            $query .= "(CAST(" . $args['date_type'] . " as DATE) >= '" . date('Y-m-d', strtotime($dates[0])) . "' AND CAST(" . $args['date_type'] . " as DATE) <= '" . date('Y-m-d', strtotime($dates[1])) . "')";
        }

        // Check if an order by and a order is given (default it is always id DESC)
        if (!empty($args['orderby']) && !empty($args['order'])) {
            $query .= "ORDER BY " . esc_sql($args['orderby']) . " " . esc_sql($args['order']) . " ";
        }

        // Set a limit if there is a post_per_page, and it is not -1 (default 10)
        if ($args['post_per_page'] != null && $args['post_per_page'] != -1) {
            $query .= "LIMIT " . esc_sql($args['post_per_page']) . " OFFSET " . (($args['paged'] - 1) * $args['post_per_page']);
        }
        // return the formatted result array
        if (!$isCount) {
            return self::format($wpdb->get_results($query));
        } else {
            return $wpdb->get_var($query);
        }
    }

    /**
     * format - transforms the database object to a formatted array
     * @param $logs
     * @return array
     */
    private static function format($logs)
    {
        $formatted_data = [];
        if (!empty($logs) && $logs != null) {
            foreach ($logs as $log) {
                $formatted_data[] = [
                    'id' => $log->id,
                    'subject' => $log->subject,
                    'sender' => $log->sender,
                    'receiver' => json_decode($log->receiver, true),
                    'cc' => json_decode($log->cc, true),
                    'bcc' => json_decode($log->bcc, true),
                    'headers' => json_decode($log->headers, true),
                    'body' => $log->body,
                    'status' => $log->status,
                    'attachments' => json_decode($log->attachments, true),
                    'backtrace' => json_decode($log->backtrace, true),
                    'created' => $log->created,
                    'updated' => $log->updated,
                    'sent' => $log->sent,
                    'receiver_status' => json_decode($log->receiver_status, true),
                ];
            }
        }
        return $formatted_data;
    }

    /**
     * save - saves new log item to the database
     * @param $args (mail_data)
     * @return int (inserted id)
     */
    public static function save($args)
    {
        global $wpdb;

        $wpdb->insert(RTM_MAIL_TABLE_PREFIX . self::TABLE_NAME, [
            'subject' => $args['subject'],
            'sender' => $args['sender'],
            'receiver' => json_encode($args['receiver']),
            'cc' => json_encode($args['cc']),
            'bcc' => json_encode($args['bcc']),
            'headers' => json_encode($args['headers']),
            'body' => $args['body'],
            'attachments' => json_encode($args['attachments']),
            'backtrace' => json_encode($args['backtrace']),
            'created' => $args['created'],
            'receiver_status' => json_encode($args['receiver_status']),
        ]);

        return $wpdb->insert_id;
    }

    /**
     * update - updates log based on id and given arguments
     * @param $log_id
     * @param $args
     */
    public static function update($log_id, $args)
    {
        global $wpdb;

        $wpdb->update(RTM_MAIL_TABLE_PREFIX . self::TABLE_NAME, $args, ['id' => $log_id]);
    }

    public static function delete($args)
    {
        global $wpdb;

        $wpdb->delete(RTM_MAIL_TABLE_PREFIX . self::TABLE_NAME, $args);
    }

    /**
     * get_total_rows - get the total amount of rows in the table
     * @return string|null
     */
    public static function get_total_rows($args = [])
    {
        $args = array_merge($args, ['post_per_page' => -1]);
        return self::get($args, true);
    }
}