<?php

declare(strict_types=1);

namespace Instinctor\Services;

use Instinctor\Core\Config;
use Instinctor\Core\DB;
use Instinctor\Core\Mailer;


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

/**
 * Inventory Service
 * Manages stock levels, notifications, and backorders
 */
class InventoryService
{
    /**
     * Get inventory settings
     */
    public static function getSettings(): array
    {
        return [
            'manage_stock' => Config::get('instinctor_manage_stock', true),
            'low_stock_threshold' => intval(Config::get('instinctor_low_stock_threshold', 5)),
            'out_of_stock_visibility' => Config::get('instinctor_out_of_stock_visibility', 'show'),
            'backorders_allowed' => Config::get('instinctor_backorders_allowed', false),
            'notify_low_stock' => Config::get('instinctor_notify_low_stock', true),
            'notify_out_of_stock' => Config::get('instinctor_notify_out_of_stock', true),
            'stock_display' => Config::get('instinctor_stock_display', 'always'), // always, low, never
        ];
    }

    /**
     * Check stock for product
     */
    public static function checkStock(int $productId, int $quantity = 1, ?int $variationId = null): array
    {
        $p = DB::prefix();

        if ($variationId) {
            $item = DB::get_row(DB::prepare(
                "SELECT stock_quantity, stock_status FROM {$p}instinctor_product_variations WHERE id = %d",
                $variationId
            ));
        } else {
            $item = DB::get_row(DB::prepare(
                "SELECT stock_quantity, stock_status, manage_stock FROM {$p}instinctor_products WHERE id = %d",
                $productId
            ));
        }

        if (!$item) {
            return ['available' => false, 'message' => 'Product not found'];
        }

        // If not managing stock, just check status
        if (!$variationId && empty($item->manage_stock)) {
            return [
                'available' => $item->stock_status === 'instock',
                'message' => $item->stock_status === 'instock' ? 'In stock' : 'Out of stock',
            ];
        }

        $stockQty = intval($item->stock_quantity);
        $settings = self::getSettings();

        if ($stockQty <= 0) {
            if ($settings['backorders_allowed']) {
                return [
                    'available' => true,
                    'backorder' => true,
                    'quantity' => 0,
                    'message' => 'Available on backorder',
                ];
            }
            return ['available' => false, 'quantity' => 0, 'message' => 'Out of stock'];
        }

        if ($stockQty < $quantity) {
            return [
                'available' => false,
                'quantity' => $stockQty,
                'message' => "Only {$stockQty} available",
            ];
        }

        $lowStock = $stockQty <= $settings['low_stock_threshold'];

        return [
            'available' => true,
            'quantity' => $stockQty,
            'low_stock' => $lowStock,
            'message' => $lowStock ? "Only {$stockQty} left!" : 'In stock',
        ];
    }

    /**
     * Reduce stock for order
     */
    public static function reduceStock(int $orderId): void
    {
        $items_table = DB::prefix() . 'instinctor_order_items';

        $items = DB::get_results(DB::prepare(
            "SELECT product_id, variation_id, quantity FROM $items_table WHERE order_id = %d",
            $orderId
        ));

        foreach ($items as $item) {
            self::adjustStock($item->product_id, -$item->quantity, $item->variation_id);
        }
    }

    /**
     * Restore stock for cancelled/refunded order
     */
    public static function restoreStock(int $orderId): void
    {
        $items_table = DB::prefix() . 'instinctor_order_items';

        $items = DB::get_results(DB::prepare(
            "SELECT product_id, variation_id, quantity FROM $items_table WHERE order_id = %d",
            $orderId
        ));

        foreach ($items as $item) {
            self::adjustStock($item->product_id, $item->quantity, $item->variation_id);
        }
    }

    /**
     * Adjust stock level
     */
    public static function adjustStock(int $productId, int $quantity, ?int $variationId = null): bool
    {

        if ($variationId) {
            $table = DB::prefix() . 'instinctor_product_variations';
            $result = DB::query(DB::prepare(
                "UPDATE $table SET stock_quantity = stock_quantity + %d WHERE id = %d",
                $quantity, $variationId
            ));

            // Update stock status
            $newQty = DB::get_var(DB::prepare("SELECT stock_quantity FROM $table WHERE id = %d", $variationId));
            DB::update($table, [
                'stock_status' => $newQty > 0 ? 'instock' : 'outofstock'
            ], ['id' => $variationId]);
        } else {
            $table = DB::prefix() . 'instinctor_products';
            $result = DB::query(DB::prepare(
                "UPDATE $table SET stock_quantity = stock_quantity + %d WHERE id = %d AND manage_stock = 1",
                $quantity, $productId
            ));

            // Update stock status
            $product = DB::get_row(DB::prepare("SELECT stock_quantity, manage_stock FROM $table WHERE id = %d", $productId));
            if ($product && $product->manage_stock) {
                DB::update($table, [
                    'stock_status' => $product->stock_quantity > 0 ? 'instock' : 'outofstock'
                ], ['id' => $productId]);
            }
        }

        // Check for notifications
        self::checkStockNotifications($productId, $variationId);

        return $result !== false;
    }

    /**
     * Set stock level
     */
    public static function setStock(int $productId, int $quantity, ?int $variationId = null): bool
    {

        if ($variationId) {
            $table = DB::prefix() . 'instinctor_product_variations';
            $result = DB::update($table, [
                'stock_quantity' => $quantity,
                'stock_status' => $quantity > 0 ? 'instock' : 'outofstock',
            ], ['id' => $variationId]);
        } else {
            $table = DB::prefix() . 'instinctor_products';
            $result = DB::update($table, [
                'stock_quantity' => $quantity,
                'stock_status' => $quantity > 0 ? 'instock' : 'outofstock',
            ], ['id' => $productId]);
        }

        self::checkStockNotifications($productId, $variationId);

        return $result !== false;
    }

    /**
     * Check and send stock notifications
     */
    private static function checkStockNotifications(int $productId, ?int $variationId = null): void
    {
        $p = DB::prefix();
        $settings = self::getSettings();

        // Get current stock
        if ($variationId) {
            $stock = DB::get_var(DB::prepare(
                "SELECT stock_quantity FROM {$p}instinctor_product_variations WHERE id = %d",
                $variationId
            ));
        } else {
            $stock = DB::get_var(DB::prepare(
                "SELECT stock_quantity FROM {$p}instinctor_products WHERE id = %d AND manage_stock = 1",
                $productId
            ));
        }

        if ($stock === null) return;

        $stock = intval($stock);

        // Low stock notification
        if ($settings['notify_low_stock'] && $stock > 0 && $stock <= $settings['low_stock_threshold']) {
            self::sendLowStockNotification($productId, $variationId, $stock);
        }

        // Out of stock notification
        if ($settings['notify_out_of_stock'] && $stock <= 0) {
            self::sendOutOfStockNotification($productId, $variationId);
        }

    }

    /**
     * Send low stock email to admin
     */
    private static function sendLowStockNotification(int $productId, ?int $variationId, int $stock): void
    {
        $p = DB::prefix();
        
        $product = DB::get_row(DB::prepare(
            "SELECT name, sku FROM {$p}instinctor_products WHERE id = %d",
            $productId
        ));

        if (!$product) return;

        // Use EmailService template
        EmailService::send('low_stock', Config::get('admin_email'), [
            'product_name' => $product->name,
            'product_sku' => $product->sku ?: 'N/A',
            'stock_quantity' => $stock,
        ]);
    }

    /**
     * Send out of stock email to admin
     */
    private static function sendOutOfStockNotification(int $productId, ?int $variationId): void
    {
        $p = DB::prefix();
        
        $product = DB::get_row(DB::prepare(
            "SELECT name, sku FROM {$p}instinctor_products WHERE id = %d",
            $productId
        ));

        if (!$product) return;

        $subject = 'Out of Stock: ' . $product->name;
        $message = sprintf(
            "The following product is now out of stock:\n\nProduct: %s\nSKU: %s\n\nView in admin: %s",
            $product->name,
            $product->sku ?: 'N/A',
            admin_url('admin.php?page=instinctor-products&action=edit&id=' . $productId)
        );

        Mailer::send(Config::get('admin_email'), $subject, $message);
    }

    /**
     * Get low stock products
     */
    public static function getLowStockProducts(): array
    {
        $table = DB::prefix() . 'instinctor_products';
        
        // Check if table exists
        if (DB::get_var("SHOW TABLES LIKE '$table'") !== $table) {
            return [];
        }
        
        $threshold = intval(Config::get('instinctor_low_stock_threshold', 5));

        return DB::get_results(DB::prepare(
            "SELECT id, name, sku, stock_quantity, stock_status
             FROM $table
             WHERE manage_stock = 1 AND stock_quantity > 0 AND stock_quantity <= %d
             ORDER BY stock_quantity ASC",
            $threshold
        )) ?: [];
    }

    /**
     * Get out of stock products
     */
    public static function getOutOfStockProducts(): array
    {
        $table = DB::prefix() . 'instinctor_products';
        
        // Check if table exists
        if (DB::get_var("SHOW TABLES LIKE '$table'") !== $table) {
            return [];
        }

        return DB::get_results(
            "SELECT id, name, sku, stock_quantity, stock_status
             FROM $table
             WHERE (manage_stock = 1 AND stock_quantity <= 0) OR stock_status = 'outofstock'
             ORDER BY name ASC"
        ) ?: [];
    }

    /**
     * Get stock report
     */
    public static function getStockReport(): array
    {
        $table = DB::prefix() . 'instinctor_products';
        $settings = self::getSettings();
        
        // Check if table exists
        if (DB::get_var("SHOW TABLES LIKE '$table'") !== $table) {
            return [
                'total_products' => 0,
                'in_stock' => 0,
                'low_stock' => 0,
                'out_of_stock' => 0,
                'backorder' => 0,
            ];
        }

        return [
            'total_products' => (int) DB::get_var("SELECT COUNT(*) FROM $table WHERE status = 'published'"),
            'in_stock' => (int) DB::get_var("SELECT COUNT(*) FROM $table WHERE status = 'published' AND stock_status = 'instock'"),
            'low_stock' => (int) DB::get_var(DB::prepare(
                "SELECT COUNT(*) FROM $table WHERE status = 'published' AND manage_stock = 1 AND stock_quantity > 0 AND stock_quantity <= %d",
                $settings['low_stock_threshold']
            )),
            'out_of_stock' => (int) DB::get_var("SELECT COUNT(*) FROM $table WHERE status = 'published' AND (stock_status = 'outofstock' OR (manage_stock = 1 AND stock_quantity <= 0))"),
            'backorder' => (int) DB::get_var("SELECT COUNT(*) FROM $table WHERE status = 'published' AND stock_status = 'onbackorder'"),
        ];
    }

    /**
     * Get stock display text for frontend
     */
    public static function getStockDisplayText(int $productId, ?int $variationId = null): string
    {
        $stock = self::checkStock($productId, 1, $variationId);
        $settings = self::getSettings();

        if ($settings['stock_display'] === 'never') {
            return $stock['available'] ? 'In stock' : 'Out of stock';
        }

        if (!$stock['available']) {
            return $stock['message'];
        }

        if ($settings['stock_display'] === 'low' && empty($stock['low_stock'])) {
            return 'In stock';
        }

        return $stock['message'];
    }
}
