<?php

namespace app\service;

use think\facade\Db;
use think\facade\Log;

class MssqlQuery
{
    private static $healthCache = [
        'available' => null,
        'checked_at' => 0
    ];
    private static $healthCheckInterval = 60;

    private static function isMssqlAvailable()
    {
        $now = time();
        if ($now - self::$healthCache['checked_at'] < self::$healthCheckInterval) {
            return self::$healthCache['available'];
        }

        try {
            Db::connect('mssql')->query('SELECT 1');
            self::$healthCache['available'] = true;
            self::$healthCache['checked_at'] = $now;
            Log::info('SQL Server 连接恢复正常');
        } catch (\Exception $e) {
            self::$healthCache['available'] = false;
            self::$healthCache['checked_at'] = $now;
            Log::warning("SQL Server 不可用（下次探测 " . self::$healthCheckInterval . "s 后）: " . $e->getMessage());
        }

        return self::$healthCache['available'];
    }

    public static function queryChuku($startDate, $endDate, $page, $limit, $isolationSql, $isolationParams)
    {
        if (!self::isMssqlAvailable()) {
            throw new \Exception('SQL Server 连接不可用');
        }

        return self::queryChukuReal($startDate, $endDate, $page, $limit, $isolationSql, $isolationParams);
    }

    private static function queryChukuReal($startDate, $endDate, $page, $limit, $isolationSql, $isolationParams)
    {
        $dateCondition = '';
        $dateParams = [];

        if ($startDate) {
            $dateCondition .= " AND x.[日期] >= :start_date";
            $dateParams['start_date'] = $startDate;
        }
        if ($endDate) {
            $dateCondition .= " AND x.[日期] <= :end_date";
            $dateParams['end_date'] = $endDate;
        }

        $startRow = ($page - 1) * $limit + 1;
        $endRow = $page * $limit;
        $countParams = array_merge($dateParams, $isolationParams);
        $dataParams = array_merge($countParams, [
            'start_row' => $startRow,
            'end_row' => $endRow
        ]);

        $sqlResult = self::buildLogSql(self::getChukuBaseSql(), $dateCondition, $isolationSql, $dataParams);
        $dataSql = $sqlResult['dataSql'];
        $logSql = $sqlResult['logSql'];

        $countSql = self::getChukuCountSql();
        $countSql = str_replace(['{date_condition}', '{isolation_condition}'], [$dateCondition, $isolationSql], $countSql);

        Log::debug("出库查询 - 统计SQL: " . $countSql);
        Log::debug("出库查询 - 统计参数: " . json_encode($countParams));
        Log::debug("出库查询 - 统计参数数量: " . count($countParams));

        try {
            $total = Db::connect('mssql')->query($countSql, $countParams);
            $total = isset($total[0]['total']) ? (int)$total[0]['total'] : 0;
            Log::debug("出库查询 - 统计成功，总数: " . $total);
        } catch (\Exception $e) {
            Log::error("出库查询 - 统计失败: " . $e->getMessage());
            Log::error("出库查询 - 统计SQL(原始): " . $countSql);
            Log::error("出库查询 - 统计参数(原始): " . json_encode($countParams));
            throw $e;
        }

        Log::debug("出库查询 - 数据SQL: " . $dataSql);
        Log::debug("出库查询 - 数据参数: " . json_encode($dataParams));
        Log::debug("出库查询 - 数据参数数量: " . count($dataParams));

        try {
            $rows = Db::connect('mssql')->query($dataSql, $dataParams);
            Log::debug("出库查询 - 数据查询成功，行数: " . count($rows));
        } catch (\Exception $e) {
            Log::error("出库查询 - 数据查询失败: " . $e->getMessage());
            Log::error("出库查询 - 数据SQL(原始): " . $dataSql);
            Log::error("出库查询 - 数据参数(原始): " . json_encode($dataParams));
            throw $e;
        }

        $records = [];
        foreach ($rows as $row) {
            $records[] = self::convertChukuRow($row);
        }

        return [
            'records' => $records,
            'total' => $total,
            'sql' => $logSql
        ];
    }

    public static function queryRuku($startDate, $endDate, $page, $limit, $isolationSql, $isolationParams)
    {
        if (!self::isMssqlAvailable()) {
            throw new \Exception('SQL Server 连接不可用');
        }

        return self::queryRukuReal($startDate, $endDate, $page, $limit, $isolationSql, $isolationParams);
    }

    private static function queryRukuReal($startDate, $endDate, $page, $limit, $isolationSql, $isolationParams)
    {
        $dateCondition = '';
        $dateParams = [];

        if ($startDate) {
            $dateCondition .= " AND x.[日期] >= :start_date";
            $dateParams['start_date'] = $startDate;
        }
        if ($endDate) {
            $dateCondition .= " AND x.[日期] <= :end_date";
            $dateParams['end_date'] = $endDate;
        }

        $startRow = ($page - 1) * $limit + 1;
        $endRow = $page * $limit;
        $countParams = array_merge($dateParams, $isolationParams);
        $dataParams = array_merge($countParams, [
            'start_row' => $startRow,
            'end_row' => $endRow
        ]);

        $sqlResult = self::buildLogSql(self::getRukuBaseSql(), $dateCondition, $isolationSql, $dataParams);
        $dataSql = $sqlResult['dataSql'];
        $logSql = $sqlResult['logSql'];

        $countSql = self::getRukuCountSql();
        $countSql = str_replace(['{date_condition}', '{isolation_condition}'], [$dateCondition, $isolationSql], $countSql);

        Log::debug("入库查询 - 统计SQL: " . $countSql);
        Log::debug("入库查询 - 统计参数: " . json_encode($countParams));

        $total = Db::connect('mssql')->query($countSql, $countParams);
        $total = isset($total[0]['total']) ? (int)$total[0]['total'] : 0;

        Log::debug("入库查询 - 数据SQL: " . $dataSql);
        Log::debug("入库查询 - 数据参数: " . json_encode($dataParams));

        $rows = Db::connect('mssql')->query($dataSql, $dataParams);

        $records = [];
        foreach ($rows as $row) {
            $records[] = self::convertRukuRow($row);
        }

        return [
            'records' => $records,
            'total' => $total,
            'sql' => $logSql
        ];
    }

    private static function buildLogSql($sqlTemplate, $dateCondition, $isolationSql, $allParams)
    {
        $dataSql = str_replace(['{date_condition}', '{isolation_condition}'], [$dateCondition, $isolationSql], $sqlTemplate);
        $logSql = $dataSql;

        foreach ($allParams as $key => $value) {
            $placeholder = ':' . $key;
            if (is_string($value)) {
                $logSql = str_replace($placeholder, "'" . $value . "'", $logSql);
            } else {
                $logSql = str_replace($placeholder, (string)$value, $logSql);
            }
        }

        return ['dataSql' => $dataSql, 'logSql' => $logSql];
    }

    private static function convertChukuRow($row)
    {
        return [
            'chuku_id' => $row['chuku_id'] ?? '',
            'ruku_id' => $row['ruku_id'] ?? '',
            'ticket_no' => $row['ticket_no'] ?? '',
            'date' => self::convertDate($row['date'] ?? null),
            'warehouse' => $row['warehouse'] ?? '',
            'batch_no' => $row['batch_no'] ?? '',
            'expire_date' => self::convertDate($row['expire_date'] ?? null),
            'quantity' => self::convertFloat($row['quantity'] ?? null),
            'unit_price' => self::convertFloat($row['unit_price'] ?? null),
            'amount' => self::convertFloat($row['amount'] ?? null),
            'purchase_price' => self::convertFloat($row['purchase_price'] ?? null),
            'profit' => self::convertFloat($row['profit'] ?? null),
            'operator' => $row['operator'] ?? '',
            'salesman' => $row['salesman'] ?? '',
            'receiver' => $row['receiver'] ?? '',
            'summary' => $row['summary'] ?? '',
            'supplier_id' => $row['supplier_id'] ?? '',
            'supplier_name' => $row['supplier_name'] ?? '',
            'supplier_short_name' => $row['supplier_short_name'] ?? '',
            'customer_id' => $row['customer_id'] ?? '',
            'customer_name' => $row['customer_name'] ?? '',
            'customer_short_name' => $row['customer_short_name'] ?? '',
            'customer_region' => $row['customer_region'] ?? '',
            'product_id' => $row['product_id'] ?? '',
            'product_name' => $row['product_name'] ?? '',
            'product_spec' => $row['product_spec'] ?? '',
            'product_origin' => $row['product_origin'] ?? '',
            'product_unit' => $row['product_unit'] ?? '',
            'manufacturer' => $row['manufacturer'] ?? '',
        ];
    }

    private static function convertRukuRow($row)
    {
        return [
            'ruku_id' => $row['ruku_id'] ?? '',
            'ticket_no' => $row['ticket_no'] ?? '',
            'date' => self::convertDate($row['date'] ?? null),
            'warehouse' => $row['warehouse'] ?? '',
            'batch_no' => $row['batch_no'] ?? '',
            'expire_date' => self::convertDate($row['expire_date'] ?? null),
            'quantity' => self::convertFloat($row['quantity'] ?? null),
            'unit_price' => self::convertFloat($row['unit_price'] ?? null),
            'amount' => self::convertFloat($row['amount'] ?? null),
            'purchase_price' => self::convertFloat($row['purchase_price'] ?? null),
            'warehouse_qty' => self::convertFloat($row['warehouse_qty'] ?? null),
            'operator' => $row['operator'] ?? '',
            'purchaser' => $row['purchaser'] ?? '',
            'responsible_person' => $row['responsible_person'] ?? '',
            'arrival_no' => $row['arrival_no'] ?? '',
            'invoice_no' => $row['invoice_no'] ?? '',
            'summary' => $row['summary'] ?? '',
            'supplier_id' => $row['supplier_id'] ?? '',
            'supplier_name' => $row['supplier_name'] ?? '',
            'supplier_short_name' => $row['supplier_short_name'] ?? '',
            'product_id' => $row['product_id'] ?? '',
            'product_name' => $row['product_name'] ?? '',
            'product_spec' => $row['product_spec'] ?? '',
            'product_origin' => $row['product_origin'] ?? '',
            'product_unit' => $row['product_unit'] ?? '',
            'manufacturer' => $row['manufacturer'] ?? '',
        ];
    }

    private static function convertDate($value)
    {
        if ($value === null) {
            return null;
        }

        if (is_numeric($value)) {
            try {
                $base = new \DateTime('1899-12-30');
                $base->add(new \DateInterval('P' . (int)$value . 'D'));
                return $base->format('Y-m-d');
            } catch (\Exception $e) {
                return (string)$value;
            }
        }

        if ($value instanceof \DateTime) {
            return $value->format('Y-m-d');
        }

        return (string)$value;
    }

    private static function convertFloat($value)
    {
        if ($value === null) {
            return null;
        }

        return is_numeric($value) ? (float)$value : null;
    }

    private static function getChukuBaseSql()
    {
        return "
            WITH PageData AS (
                SELECT
                    ROW_NUMBER() OVER (ORDER BY x.[日期] DESC) AS RowID,
                    x.[出库序号] AS chuku_id,
                    x.[入库序号] AS ruku_id,
                    x.[票号] AS ticket_no,
                    x.[日期] AS date,
                    x.[库房] AS warehouse,
                    x.[批号] AS batch_no,
                    x.[效期] AS expire_date,
                    x.[数量] AS quantity,
                    x.[单价] AS unit_price,
                    x.[金额] AS amount,
                    x.[进价] AS purchase_price,
                    x.[毛利] AS profit,
                    x.[操作员] AS operator,
                    x.[业务员] AS salesman,
                    x.[提货人] AS receiver,
                    x.[摘要] AS summary,
                    x.[供方序号] AS supplier_id,
                    k.[供方全称] AS supplier_name,
                    k.[简称] AS supplier_short_name,
                    x.[销方序号] AS customer_id,
                    f.[销方全称] AS customer_name,
                    f.[简称] AS customer_short_name,
                    f.[地区] AS customer_region,
                    x.[产品序号] AS product_id,
                    p.[产品名称] AS product_name,
                    p.[规格] AS product_spec,
                    p.[产地] AS product_origin,
                    p.[单位] AS product_unit,
                    p.[生产厂家] AS manufacturer
                FROM [ywsj].[dbo].[vckmx] x
                JOIN [ywsj].[dbo].[bgfkh] k ON x.[供方序号] = k.[供方序号]
                JOIN [ywsj].[dbo].[bcp] p ON x.[产品序号] = p.[产品序号]
                JOIN [ywsj].[dbo].[bxfkh] f ON x.[销方序号] = f.[销方序号]
                WHERE 1=1
                {date_condition}
                {isolation_condition}
            )
            SELECT
                chuku_id, ruku_id, ticket_no, date, warehouse, batch_no, expire_date,
                quantity, unit_price, amount, purchase_price, profit,
                operator, salesman, receiver, summary,
                supplier_id, supplier_name, supplier_short_name,
                customer_id, customer_name, customer_short_name, customer_region,
                product_id, product_name, product_spec, product_origin,
                product_unit, manufacturer
            FROM PageData
            WHERE RowID BETWEEN :start_row AND :end_row
            ORDER BY RowID
        ";
    }

    private static function getChukuCountSql()
    {
        return "
            SELECT COUNT(*) AS total
            FROM [ywsj].[dbo].[vckmx] x
            JOIN [ywsj].[dbo].[bgfkh] k ON x.[供方序号] = k.[供方序号]
            JOIN [ywsj].[dbo].[bcp] p ON x.[产品序号] = p.[产品序号]
            JOIN [ywsj].[dbo].[bxfkh] f ON x.[销方序号] = f.[销方序号]
            WHERE 1=1
            {date_condition}
            {isolation_condition}
        ";
    }

    private static function getRukuBaseSql()
    {
        return "
            WITH PageData AS (
                SELECT
                    ROW_NUMBER() OVER (ORDER BY x.[日期] DESC) AS RowID,
                    x.[入库序号] AS ruku_id,
                    x.[票号] AS ticket_no,
                    x.[日期] AS date,
                    x.[库房] AS warehouse,
                    x.[批号] AS batch_no,
                    x.[效期] AS expire_date,
                    x.[数量] AS quantity,
                    x.[单价] AS unit_price,
                    x.[金额] AS amount,
                    x.[进价] AS purchase_price,
                    x.[库房数量] AS warehouse_qty,
                    x.[操作员] AS operator,
                    x.[采购员] AS purchaser,
                    x.[负责人] AS responsible_person,
                    x.[来货单号] AS arrival_no,
                    x.[发票单号] AS invoice_no,
                    x.[摘要] AS summary,
                    x.[供方序号] AS supplier_id,
                    k.[供方全称] AS supplier_name,
                    k.[简称] AS supplier_short_name,
                    x.[产品序号] AS product_id,
                    p.[产品名称] AS product_name,
                    p.[规格] AS product_spec,
                    p.[产地] AS product_origin,
                    p.[单位] AS product_unit,
                    p.[生产厂家] AS manufacturer
                FROM [ywsj].[dbo].[vrkmx] x
                JOIN [ywsj].[dbo].[bgfkh] k ON x.[供方序号] = k.[供方序号]
                JOIN [ywsj].[dbo].[bcp] p ON x.[产品序号] = p.[产品序号]
                WHERE 1=1
                {date_condition}
                {isolation_condition}
            )
            SELECT
                ruku_id, ticket_no, date, warehouse, batch_no, expire_date,
                quantity, unit_price, amount, purchase_price, warehouse_qty,
                operator, purchaser, responsible_person, arrival_no, invoice_no,
                summary, supplier_id, supplier_name, supplier_short_name,
                product_id, product_name, product_spec, product_origin,
                product_unit, manufacturer
            FROM PageData
            WHERE RowID BETWEEN :start_row AND :end_row
            ORDER BY RowID
        ";
    }

    private static function getRukuCountSql()
    {
        return "
            SELECT COUNT(*) AS total
            FROM [ywsj].[dbo].[vrkmx] x
            JOIN [ywsj].[dbo].[bgfkh] k ON x.[供方序号] = k.[供方序号]
            JOIN [ywsj].[dbo].[bcp] p ON x.[产品序号] = p.[产品序号]
            WHERE 1=1
            {date_condition}
            {isolation_condition}
        ";
    }
}
