<?php

if (!defined('ABSPATH')) {
    exit; // Exit if accessed directly.
}


/**
 * insert invoice into database
 *
 * @param  array $data
 * @return mixed
 */
function salesloo_insert_invoice($data = [])
{
    $data = apply_filters('salelsoo/invoice/insert/data', $data);

    if (empty($data) || !is_array($data)) return false;

    $invoice_args = [];

    foreach (Salesloo\Models\Invoice::get_columns() as $key => $type) {

        if (isset($data[$key])) {
            $invoice_args[$key] = $data[$key];
        }
    }

    $invoice_id = Salesloo\Models\Invoice::data($invoice_args)->create();

    if (!is_wp_error($invoice_id) && isset($data['orders'])) {
        foreach ((array)$data['orders'] as $order_id) {
            \Salesloo\Models\Invoice_Order::data(['invoice_id' => $invoice_id, 'order_id' => $order_id])->create();
        }
    }

    return $invoice_id;
}


/**
 * update invoice
 *
 * @param  array $data
 * @return mixed
 */
function salesloo_update_invoice($data = [])
{
    $data = apply_filters('salelsoo/invoice/update/data', $data);

    if (empty($data) || !is_array($data)) return false;

    $invoice_id = isset($data['ID']) ? intval($data['ID']) : 0;

    $invoice_args = [];
    foreach (Salesloo\Models\Invoice::get_columns() as $key => $type) {

        if ('ID' == $key) continue;

        if (isset($data[$key])) {
            $invoice_args[$key] = $data[$key];
        }
    }

    $invoice = salesloo_get_invoice($invoice_id);
    if (false === $invoice) {
        return salesloo_insert_invoice($invoice_args);
    }

    $updated = Salesloo\Models\Invoice::data($invoice_args)->update([
        'ID' => $invoice_id,
    ]);

    if (!is_wp_error($updated)) {
        \Salesloo\Models\Invoice_Order::delete(['invoice_id' => $invoice->ID]);

        foreach ((array)$data['orders'] as $order_id) {
            \Salesloo\Models\Invoice_Order::data(['invoice_id' => $invoice_id, 'order_id' => $order_id])->create();
        }
    }

    return $updated;
}


/**
 * delete invoice
 *
 * @param  mixed $invoice
 * @return mixed
 */
function salesloo_delete_invoice($invoice)
{
    $invoice = salesloo_get_invoice($invoice);

    if (false === $invoice) return $invoice;

    $deleted = Salesloo\Models\Invoice::delete(['ID' => $invoice->ID]);

    return $deleted;
}


/**
 * get single invoice
 *
 * @param  mixed $invoice
 * @return mixed
 */
function salesloo_get_invoice($invoice = null)
{

    if (is_object($invoice) && isset($invoice->ID)) :
        $invoice_id = intval($invoice->ID);
    elseif (is_array($invoice) && isset($invoice['ID'])) :
        $invoice_id = intval($invoice['ID']);
    elseif (is_int($invoice) || is_string($invoice)) :
        $invoice_id = intval($invoice);
    else :
        return false;
    endif;

    $invoice = Salesloo\Models\Invoice::query('WHERE ID = %d', $invoice_id)->first();

    return $invoice->ID > 0 ? $invoice : false;
}


/**
 * get invoice orders
 *
 * @param  int $invoice_id
 * @return mixed
 */
function salesloo_get_invoice_orders($invoice_id)
{
    $orders = \Salesloo\Models\Order::join('left', 'salesloo_invoice_order', ['ID', 'order_id', '='])
        ->select(
            ['salesloo_order', '*'],
            ['salesloo_invoice_order', 'invoice_id']
        )
        ->query('WHERE invoice_id = %d', $invoice_id)
        ->get();

    return $orders;
}


/**
 * generate invoice format by invoice ID
 *
 * @param  int $invoice_id
 * @return string
 */
function salesloo_generate_invoice_format($invoice_id)
{
    $format = salesloo_get_option('invoice_format');
    list($y, $m, $d) = explode('-', date('Y-m-d', strtotime('now')));

    $number = str_pad($invoice_id, 5, "0", STR_PAD_LEFT);

    $format = str_replace('{year}', $y, $format);
    $format = str_replace('{month}', $m, $format);
    $format = str_replace('{date}', $d, $format);
    $format = str_replace('{number}', $number, $format);

    return $format;
}


/**
 * set invoice due date
 *
 * @return string
 */
function salesloo_set_invoice_due_date()
{
    $duration = salesloo_get_option('invoice_due_date_duration');

    if (intval($duration) <= 0) {
        $duration = 7;
    }

    return date('Y-m-d H:i:s', strtotime('+' . $duration . 'days'));
}

/**
 * get invoice statuses
 *
 * @param  string $status
 * @return mixed
 */
function salesloo_get_invoice_statuses($status = false)
{
    $statuses = [
        'unpaid'           => __('Unpaid', 'salesloo'),
        'checking_payment' => __('Checking Payment', 'salesloo'),
        'completed'        => __('Completed', 'salesloo'),
        'refunded'         => __('Refunded', 'salesloo'),
        'cancelled'        => __('Cancelled', 'salesloo')
    ];

    $statuses = apply_filters('salesloo/invoice/statuses', $statuses, $status);

    if ($status) {
        return isset($statuses[$status]) ? $statuses[$status] : false;
    }

    return $statuses;
}

/**
 * update invoice status
 *
 * @param  int $invoice_id
 * @param  string $status
 * @return mixed
 */
function salesloo_update_invoice_status($invoice_id, $status)
{
    global $wpdb;

    $is_status_exists = salesloo_get_invoice_statuses($status);
    if (false === $is_status_exists) {
        return new WP_Error('error', __('Invalid invoice status', 'salesloo'));
    }

    $invoice = salesloo_get_invoice(intval($invoice_id));

    $old_status = $invoice->status;

    if (false === $invoice) {
        return new WP_Error('error', __('Invalid invoice', 'salesloo'));
    }

    if ($status == $old_status) {
        return new WP_Error('error', __('Status can not be updated because previous status has ' . $status . ' status', 'salesloo'));
    }

    $invoice_args = [
        'status' => $status,
        'updated_at' => date('Y-m-d H:i:s')
    ];

    do_action('salesloo/update/invoice/status/before', $invoice_id, $status, $old_status);

    $updated = Salesloo\Models\Invoice::data($invoice_args)->update([
        'ID' => $invoice_id,
    ]);

    do_action('salesloo/update/invoice/status', $invoice_id);

    if (is_wp_error($updated)) {
        return $updated;
    }

    $invoice = salesloo_get_invoice($invoice_id);
    $orders = $invoice->orders();

    $order_ids = [];
    foreach ($orders as $order) {
        $order_ids[] = intval($order->ID);

        salesloo_invoice_update_order_status($invoice->ID, $order->ID, $order->status);
    }

    /**
     * update commission status from pending to unpaid if completed invoice status
     */
    if ($order_ids) {
        $order_ids = implode(',', $order_ids);
        $table = $wpdb->prefix . 'salesloo_commission';
        $query = "UPDATE $table SET status = %s WHERE order_id IN ($order_ids) AND status != %s";

        if ('completed' == $status) {
            $wpdb->query($wpdb->prepare($query, 'unpaid', 'paid'));
        } elseif ($status == 'unpaid' || $status == 'checking_payment') {
            $wpdb->query($wpdb->prepare($query, 'pending', 'paid'));
        } elseif ($status == 'refunded' || $status == 'cancelled') {
            $wpdb->query($wpdb->prepare($query, 'cancelled', 'paid'));
        }
    }

    $data = [
        'invoice_id' => $invoice_id
    ];
    salesloo_add_notification('invoice_' . $status, $data);
    salesloo_add_event('invoice_' . $status, $data);
    return true;
}


/**
 * salesloo_invoice_update_order_status
 *
 * @param  mixed $invoice
 * @param  mixed $order
 * @return void
 */
function salesloo_invoice_update_order_status($invoice_id, $order_id, $old_order_status)
{
    $invoice = salesloo_get_invoice($invoice_id);
    $order   = salesloo_get_order($order_id);
    $product = salesloo_get_product($order->product_id);

    $status = 'inactive';
    $log = sprintf(__('Payment %s', 'salesloo'), salesloo_get_invoice_statuses($invoice->status));

    $status = 'completed' == $invoice->status ? 'active' : 'inactive';
    $log = 'completed' == $invoice->status ? __('Order Activated', 'salesloo') : sprintf(__('Payment %s', 'salesloo'), salesloo_get_invoice_statuses($invoice->status));

    if ('completed' == $invoice->status) {
        $log = __('Order Activated', 'salesloo');
        $duration = $order->meta('duration') ? $order->meta('duration') : $product->duration;
        $duration = $duration ? $duration : 'onetime';
        $expired_date = 'onetime' == $duration ? 'NULL' : date('Y-m-d', strtotime('+ ' . $duration));

        if ($invoice->type = 'renew_order') {
            $log = __('Order Renewed', 'salesloo');

            if (strtotime($order->expired_at) > strtotime('now') && $duration != 'onetime') {
                $expired_date = date('Y-m-d', strtotime($order->expired_at . ' + ' . $duration));
            }

            if ($duration == 'onetime') {
                $expired_date = 'NULL';
            }
        }

        $updated = salesloo_update_order([
            'ID' => $order_id,
            'expired_at' => $expired_date == 'NULL' ? 'NULL' : date('Y-m-d H:i:s', strtotime($expired_date)),
            'status' => $status
        ]);
    } else {
        $updated = salesloo_update_order_status($order_id, $status);
    }

    if (!is_wp_error($updated)) {
        salesloo_insert_order_log($order_id, $log);
        salesloo_update_order_access($order_id);
        do_action('salesloo/update/order/status', $order_id, $status, $old_order_status);
    }

    return $updated;
}
