<?php
namespace Formipay;
use Formipay\Traits\SingletonTrait;

if ( ! defined( 'ABSPATH' ) ) exit;

class License {
    use SingletonTrait;

    const DB_VERSION_OPTION = 'formipay_licenses_db_version';

    protected function __construct() {
        // DB & boot
        add_action('init', [$this, 'create_db']);

        // Admin
        add_action('admin_menu', [$this, 'add_menu']);
        add_action('admin_enqueue_scripts', [$this, 'enqueue']);

        // Admin AJAX
        add_action('wp_ajax_formipay-tabledata-licenses', [$this, 'tabledata']);
        add_action('wp_ajax_formipay-delete-license', [$this, 'delete']);
        add_action('wp_ajax_formipay-bulk-delete-license', [$this, 'bulk_delete']);

        // Issue on order lifecycle
        add_action('formipay/order/completed', [$this, 'issue_for_order']);
        add_action('formipay/order/new', [$this, 'maybe_issue_for_new_order']);

        // Inject product settings via Product's filter surface
        add_filter('formipay/product-config', [$this, 'inject_product_fields'], 65);
    }

    /** Create/upgrade licenses table */
    public function create_db() {
        global $wpdb; $charset_collate = $wpdb->get_charset_collate();
        $table = $wpdb->prefix . 'formipay_licenses';
        $sql = "CREATE TABLE `$table` (
            `id` bigint(20) NOT NULL AUTO_INCREMENT,
            `created_date` datetime DEFAULT CURRENT_TIMESTAMP,
            `updated_date` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            `order_id` bigint(20) NOT NULL,
            `form_id` int(11) NOT NULL,
            `customer_email` varchar(191) NULL,
            `license_key` varchar(191) NOT NULL,
            `status` varchar(20) DEFAULT 'active',
            `expires_at` datetime NULL,
            `meta_data` longtext NULL,
            PRIMARY KEY (`id`),
            KEY `order_id` (`order_id`),
            KEY `form_id` (`form_id`),
            KEY `customer_email` (`customer_email`),
            KEY `status` (`status`),
            KEY `expires_at` (`expires_at`)
        ) $charset_collate;";
        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        dbDelta($sql);
        // TODO: set/update self::DB_VERSION_OPTION if needed
    }

    /** Add Licenses submenu */
    public function add_menu() {
        add_submenu_page(
            'formipay',
            __('Licenses', 'formipay'),
            __('Licenses', 'formipay'),
            'manage_options',
            'formipay-licenses',
            [$this, 'page_licenses']
        );
    }

    public function page_licenses() {
        include FORMIPAY_PATH . 'admin/page-licenses.php';
    }

    /** Enqueue admin assets for Licenses page */
    public function enqueue() {
        global $current_screen; if (!$current_screen) return;
        if ($current_screen->id === 'formipay_page_formipay-licenses') {
            wp_enqueue_style('page-licenses', FORMIPAY_URL . 'admin/assets/css/admin-licenses.css', [], FORMIPAY_VERSION, 'all');
            wp_enqueue_script('page-licenses', FORMIPAY_URL . 'admin/assets/js/admin-licenses.js', ['jquery', 'gridjs'], FORMIPAY_VERSION, true);
            wp_localize_script('page-licenses', 'formipay_licenses_page', [
                'ajax_url' => admin_url('admin-ajax.php'),
                'site_url' => site_url(),
                'columns' => [
                    'id' => __('ID','formipay'),
                    'product' => __('Product','formipay'),
                    'order' => __('Order','formipay'),
                    'email' => __('Email','formipay'),
                    'key' => __('Key','formipay'),
                    'status' => __('Status','formipay'),
                    'expiry' => __('Expiry','formipay'),
                    'date' => __('Date','formipay'),
                ],
                'filter_form' => [
                    'products' => [
                        'placeholder' => __('Filter by Product','formipay'),
                        'noresult_text' => __('No results found','formipay')
                    ],
                    'status' => [
                        'placeholder' => __('Filter by Status','formipay'),
                        'noresult_text' => __('No results found','formipay')
                    ]
                ],
                'modal' => [
                    'delete' => [
                        'question' => __('Do you want to delete the license?','formipay'),
                        'cancelButton' => __('Cancel','formipay'),
                        'confirmButton' => __('Delete Permanently','formipay')
                    ],
                    'bulk_delete' => [
                        'question' => __('Do you want to delete the selected license(s)?','formipay'),
                        'cancelButton' => __('Cancel','formipay'),
                        'confirmButton' => __('Confirm','formipay')
                    ],
                ],
                'nonce' => wp_create_nonce('formipay-admin-licenses')
            ]);
        }
    }

    /** GridJS data source */
    public function tabledata() {
        check_ajax_referer('formipay-admin-licenses', '_wpnonce');

        global $wpdb;
        $table = $wpdb->prefix . 'formipay_licenses';

        // Filters / params
        $status  = isset($_REQUEST['status'])  ? sanitize_text_field(wp_unslash($_REQUEST['status']))  : 'all';
        $product = isset($_REQUEST['product']) ? (int) $_REQUEST['product'] : 0;
        $search  = isset($_REQUEST['search'])  ? sanitize_text_field(wp_unslash($_REQUEST['search']))  : '';
        $limit   = isset($_REQUEST['limit'])   ? max(1, (int)$_REQUEST['limit']) : 20;
        $offset  = isset($_REQUEST['offset'])  ? max(0, (int)$_REQUEST['offset']) : 0;

        $wheres = ["`id` > %d"];
        $args   = [0];

        if ($status && $status !== 'all') {
            $wheres[] = "`status` = %s";
            $args[]   = $status;
        }
        if ($product > 0) {
            $wheres[] = "`form_id` = %d";
            $args[]   = $product;
        }
        if ($search !== '') {
            // search in email or tail of license key
            $wheres[] = "(`customer_email` LIKE %s OR `license_key` LIKE %s)";
            $like = '%' . $wpdb->esc_like($search) . '%';
            $args[] = $like;
            $args[] = $like;
        }

        $where_sql = implode(' AND ', $wheres);

        // Total count
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
        $total = (int) $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM $table WHERE $where_sql",
            $args
        ));

        // Results page
        $args_page = $args;
        $args_page[] = (int)$offset;
        $args_page[] = (int)$limit;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
        $rows = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM $table WHERE $where_sql ORDER BY `id` DESC LIMIT %d, %d",
            $args_page
        ), ARRAY_A);

        $results = [];
        if (!empty($rows)) {
            foreach ($rows as $r) {
                $pid   = (int)$r['form_id'];
                $title = $pid ? get_the_title($pid) : '';
                $results[] = [
                    'ID'     => (int)$r['id'],
                    'title'  => $title,
                    'order'  => (int)$r['order_id'],
                    'email'  => $r['customer_email'],
                    'key'    => $this->mask_key($r['license_key']),
                    'status' => $this->compute_effective_status($r),
                    'expiry' => $r['expires_at'],
                    'date'   => $r['created_date'],
                ];
            }
        }

        wp_send_json([
            'results' => $results,
            'total'   => $total,
        ]);
    }

    /** Delete single license */
    public function delete() {
        check_ajax_referer('formipay-admin-licenses', '_wpnonce');

        if (empty($_REQUEST['id'])) {
            wp_send_json_error([
                'title' => esc_html__('Failed', 'formipay'),
                'message' => esc_html__('License id is missing.', 'formipay'),
                'icon' => 'error'
            ]);
        }

        global $wpdb;
        $id = (int) $_REQUEST['id'];
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
        $deleted = $wpdb->delete($wpdb->prefix.'formipay_licenses', ['id' => $id], ['%d']);

        if ($deleted) {
            wp_send_json_success([
                'title'   => esc_html__('Deleted', 'formipay'),
                'message' => esc_html__('License is deleted permanently.', 'formipay'),
                'icon'    => 'success'
            ]);
        }

        wp_send_json_error([
            'title' => esc_html__('Failed', 'formipay'),
            'message' => esc_html__('Failed to delete license. Please try again.', 'formipay'),
            'icon' => 'error'
        ]);
    }

    /** Bulk delete */
    public function bulk_delete() {
        check_ajax_referer('formipay-admin-licenses', '_wpnonce');

        $ids = isset($_REQUEST['ids']) ? (array) $_REQUEST['ids'] : [];
        if (empty($ids)) {
            wp_send_json_error([
                'title' => esc_html__('Failed', 'formipay'),
                'message' => esc_html__('There is no license selected. Please try again.', 'formipay'),
                'icon' => 'error'
            ]);
        }

        global $wpdb;
        $success = 0; $failed = 0;
        foreach ($ids as $id) {
            $id = (int)$id;
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
            $deleted = $wpdb->delete($wpdb->prefix.'formipay_licenses', ['id' => $id], ['%d']);
            if ($deleted) $success++; else $failed++;
        }

        $report = '';
        if ($success > 0) $report .= sprintf(__(' Deleted %d license(s).', 'formipay'), $success);
        if ($failed  > 0) $report .= sprintf(__(' Failed %d license(s).', 'formipay'), $failed);

        wp_send_json_success([
            'title'   => esc_html__('Done!', 'formipay'),
            'message' => trim($report) ?: esc_html__('No changes.', 'formipay'),
            'icon'    => 'info'
        ]);
    }

    /** Issue on completed order */
    public function issue_for_order($order) {
        global $wpdb;

        if (empty($order)) return;

        // $order might be object (stdClass) or array (from filter/get)
        $row = is_array($order) ? (object)$order : $order;
        if (empty($row->id)) return;

        // Unserialize DB columns if needed
        $items     = isset($row->items) ? maybe_unserialize($row->items) : [];
        $formData  = isset($row->form_data) ? maybe_unserialize($row->form_data) : [];
        $metaData  = isset($row->meta_data) ? maybe_unserialize($row->meta_data) : [];
        $form_id   = isset($row->form_id) ? (int)$row->form_id : 0;

        // Quantity: prefer top-level qty in stored order_data; fallback to 1
        $qty = 1;
        if (is_array($formData) && isset($formData['qty'])) {
            $qty = max(1, (int)$formData['qty']);
        } elseif (is_array($items) && !empty($items[0]['qty'])) {
            $qty = max(1, (int)$items[0]['qty']);
        }

        if ($form_id <= 0) return;

        // Read product license settings
        $settings = $this->get_product_license_settings($form_id);
        if (!$settings['enabled']) return;

        // Idempotency: if per-qty is ON, expect qty rows; else expect 1 row
        $expected = $settings['per_qty'] ? $qty : 1;
        $already  = (int)$wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}formipay_licenses WHERE order_id=%d AND form_id=%d",
                (int)$row->id, (int)$form_id
            )
        );
        if ($already >= $expected) return; // already issued enough

        $to_issue = max(0, $expected - $already);
        if ($to_issue < 1) return;

        // Try to find buyer email from the submitted form payload
        $customer_email = $this->extract_email_from_order($formData);

        $issued = [];
        for ($i = 0; $i < $to_issue; $i++) {
            $plain_key  = apply_filters('formipay/license/generate_key', $this->generate_key(), $row, $form_id, $i);
            $expires_at = $settings['expiry_days'] > 0
                ? gmdate('Y-m-d H:i:s', time() + ($settings['expiry_days'] * DAY_IN_SECONDS))
                : null;

            $row_data = [
                'order_id'       => (int)$row->id,
                'form_id'        => (int)$form_id,
                'customer_email' => sanitize_text_field($customer_email),
                'license_key'    => sanitize_text_field($plain_key),
                'status'         => 'active',
                'expires_at'     => $expires_at,
                'meta_data'      => maybe_serialize([
                    'activations' => [
                        'max'    => (int)$settings['max_activations'],
                        'count'  => 0,
                        'devices'=> []
                    ]
                ]),
            ];

            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
            $wpdb->insert($wpdb->prefix.'formipay_licenses', $row_data);
            $row_data['id'] = (int)$wpdb->insert_id;
            $issued[] = $row_data;
        }

        if (!empty($issued)) {
            /**
             * Fires after license rows are issued for an order.
             *
             * @param array $issued Rows that were created.
             * @param object $order Original order object/row.
             */
            do_action('formipay/license/issued', $issued, $row);
        }
    }

    /** Catch immediate completed orders */
    public function maybe_issue_for_new_order($order) {
        $row = is_array($order) ? (object)$order : $order;
        if (!empty($row->status) && $row->status === 'completed') {
            $this->issue_for_order($row);
        }
    }

    /** Add small Licensing fields into Product General tab */
    public function inject_product_fields($fields) {
        // Inject a tiny group under General tab (consistent with your structure)
        $group = [
            'setting_product_licensing' => [
                'type'  => 'group_title',
                'label' => __('Licensing', 'formipay'),
                'description' => __('Enable license issuance for this product.', 'formipay'),
                'group' => 'started'
            ],
            '_formipay_license_enabled' => [
                'type' => 'checkbox',
                'label' => __('Enable License', 'formipay'),
            ],
            '_formipay_license_per_quantity' => [
                'type' => 'checkbox',
                'label' => __('Issue per Quantity', 'formipay'),
                'value' => true,
                'dependency' => array(
                    'key' => '_formipay_license_enabled',
                    'value' => 'not_empty'
                ),
            ],
            '_formipay_license_expiry_days' => [
                'type' => 'number',
                'label' => __('Expiry (days)', 'formipay'),
                'value' => 0,
                'dependency' => array(
                    'key' => '_formipay_license_enabled',
                    'value' => 'not_empty'
                ),
            ],
            '_formipay_license_max_activations' => [
                'type' => 'number',
                'label' => __('Max Activations', 'formipay'),
                'value' => 1,
                'dependency' => array(
                    'key' => '_formipay_license_enabled',
                    'value' => 'not_empty'
                )
            ],
        ];
        $last = array_key_last($group);
        $group[$last]['group'] = 'ended';

        $fields['formipay_product_settings']['licenses'] = array(
            'name' => __('Licensing', 'formipay'),
            'fields' => $group
        );
        return $fields;
    }

    // === Helpers (signatures only) ===

    /** Return masked key tail for UI */
    private function mask_key($key) {
        $len = strlen($key);
        if ($len <= 8) return $key;
        return substr($key, 0, 4) . str_repeat('*', $len - 8) . substr($key, -4);
    }

    /** Compute effective status (treat past-expiry as expired) */
    private function compute_effective_status($row) {
        $status = is_array($row) ? ($row['status'] ?? '') : ($row->status ?? '');
        $expires = is_array($row) ? ($row['expires_at'] ?? null) : ($row->expires_at ?? null);

        if ($status === 'active' && !empty($expires)) {
            // Compare in UTC
            $now = gmdate('Y-m-d H:i:s');
            if ($expires < $now) return 'expired';
        }
        return $status ?: 'active';
    }

    /** Read product license settings */
    private function get_product_license_settings($form_id) { 
        $enabled          = (bool) get_post_meta($form_id, '_formipay_license_enabled', true);
        $per_qty          = (bool) get_post_meta($form_id, '_formipay_license_per_quantity', true);
        $expiry_days      = (int)  get_post_meta($form_id, '_formipay_license_expiry_days', true);
        $max_activations  = (int)  get_post_meta($form_id, '_formipay_license_max_activations', true);

        return [
            'enabled'         => $enabled,
            'per_qty'         => $per_qty,
            'expiry_days'     => max(0, $expiry_days),
            'max_activations' => $max_activations > 0 ? $max_activations : 1,
        ];
    }

    /** Generate a random human-friendly license key */
    private function generate_key() {
        // 20 hex chars => split in groups of 4: XXXX-XXXX-XXXX-XXXX-XXXX
        $hex = strtoupper(bin2hex(random_bytes(10)));
        return implode('-', str_split($hex, 4));
    }

    /** Try to extract buyer email from stored order_data payload */
    private function extract_email_from_order($formData) {
        if (!is_array($formData)) return '';
        // If payload structure is like ['form_data' => [field => ['value' => ...]]]
        if (isset($formData['form_data']) && is_array($formData['form_data'])) {
            foreach ($formData['form_data'] as $k => $v) {
                $val = is_array($v) && isset($v['value']) ? $v['value'] : $v;
                if (is_string($val) && filter_var($val, FILTER_VALIDATE_EMAIL)) {
                    return $val;
                }
            }
        }
        // Also check first level
        foreach ($formData as $k => $v) {
            if (is_string($v) && filter_var($v, FILTER_VALIDATE_EMAIL)) {
                return $v;
            }
            if (is_array($v) && isset($v['value']) && filter_var($v['value'], FILTER_VALIDATE_EMAIL)) {
                return $v['value'];
            }
        }
        return '';
    }
}