<?php

namespace Modules\LotesSeries\Services;

use PDO;
use Exception;

/**
 * Serviço para rastreabilidade de lotes e séries
 */
class RastreabilidadeService {
    private PDO $pdo;
    private string $tenantId;

    public function __construct(string $tenantId) {
        $this->tenantId = $tenantId;
        $this->pdo = \Gestoreasy\Core\Tenant\ConnectionManager::forTenant($tenantId);
    }

    /**
     * Rastreia um lote completo
     */
    public function rastrearLote(int $loteId): array {
        // Buscar lote
        $stmt = $this->pdo->prepare('
            SELECT l.*, p.codigo as produto_codigo, p.nome as produto_nome
            FROM product_lots l
            INNER JOIN products p ON l.product_id = p.id
            WHERE l.id = ? AND l.tenant_id = ?
        ');
        $stmt->execute([$loteId, $this->tenantId]);
        $lote = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$lote) {
            throw new Exception('Lote não encontrado');
        }

        // Buscar movimentações
        $stmt = $this->pdo->prepare('
            SELECT * FROM lot_movements
            WHERE lot_id = ? AND tenant_id = ?
            ORDER BY created_at ASC
        ');
        $stmt->execute([$loteId, $this->tenantId]);
        $movimentacoes = $stmt->fetchAll(PDO::FETCH_ASSOC);

        // Buscar vendas relacionadas
        $vendas = $this->buscarVendasPorLote($loteId);

        return [
            'lote' => $lote,
            'movimentacoes' => $movimentacoes,
            'vendas' => $vendas,
            'rastreabilidade_completa' => true
        ];
    }

    /**
     * Rastreia um número de série completo
     */
    public function rastrearSerie(int $serieId): array {
        // Buscar série
        $stmt = $this->pdo->prepare('
            SELECT s.*, p.codigo as produto_codigo, p.nome as produto_nome,
                   c.nome as cliente_nome, c.email as cliente_email
            FROM product_serial_numbers s
            INNER JOIN products p ON s.product_id = p.id
            LEFT JOIN clients c ON s.cliente_id = c.id
            WHERE s.id = ? AND s.tenant_id = ?
        ');
        $stmt->execute([$serieId, $this->tenantId]);
        $serie = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$serie) {
            throw new Exception('Série não encontrada');
        }

        // Buscar movimentações
        $stmt = $this->pdo->prepare('
            SELECT * FROM serial_movements
            WHERE serial_id = ? AND tenant_id = ?
            ORDER BY created_at ASC
        ');
        $stmt->execute([$serieId, $this->tenantId]);
        $movimentacoes = $stmt->fetchAll(PDO::FETCH_ASSOC);

        // Buscar venda se houver
        $venda = null;
        if ($serie['venda_id']) {
            $stmt = $this->pdo->prepare('SELECT * FROM sales_orders WHERE id = ?');
            $stmt->execute([$serie['venda_id']]);
            $venda = $stmt->fetch(PDO::FETCH_ASSOC);
        }

        return [
            'serie' => $serie,
            'movimentacoes' => $movimentacoes,
            'venda' => $venda,
            'rastreabilidade_completa' => true
        ];
    }

    /**
     * Rastreia todos os lotes e séries de um produto
     */
    public function rastrearProduto(int $productId): array {
        // Buscar lotes
        $stmt = $this->pdo->prepare('
            SELECT * FROM product_lots
            WHERE product_id = ? AND tenant_id = ?
            ORDER BY created_at DESC
        ');
        $stmt->execute([$productId, $this->tenantId]);
        $lotes = $stmt->fetchAll(PDO::FETCH_ASSOC);

        // Buscar séries
        $stmt = $this->pdo->prepare('
            SELECT * FROM product_serial_numbers
            WHERE product_id = ? AND tenant_id = ?
            ORDER BY created_at DESC
        ');
        $stmt->execute([$productId, $this->tenantId]);
        $series = $stmt->fetchAll(PDO::FETCH_ASSOC);

        return [
            'lotes' => $lotes,
            'series' => $series,
            'total_lotes' => count($lotes),
            'total_series' => count($series)
        ];
    }

    /**
     * Cria um recall de produtos
     */
    public function criarRecall(array $dados): int {
        $this->pdo->beginTransaction();
        try {
            // Criar recall
            $stmt = $this->pdo->prepare('
                INSERT INTO product_recalls (
                    tenant_id, product_id, titulo, descricao,
                    criterio_tipo, criterio_valor, status, data_inicio
                ) VALUES (?, ?, ?, ?, ?, ?, "ativo", CURDATE())
            ');
            $stmt->execute([
                $this->tenantId,
                $dados['product_id'] ?? null,
                $dados['titulo'],
                $dados['descricao'],
                $dados['criterio_tipo'],
                $dados['criterio_valor'] ?? null,
            ]);

            $recallId = (int)$this->pdo->lastInsertId();

            // Identificar produtos/lotes/séries afetados
            $afetados = $this->identificarAfetados($dados);
            $this->atualizarStatusAfetados($dados['criterio_tipo'], $afetados);

            // Criar registros de clientes afetados
            $this->criarClientesAfetados($recallId, $afetados);

            // Atualizar contadores
            $stmt = $this->pdo->prepare('
                UPDATE product_recalls
                SET lotes_afetados = ?,
                    series_afetadas = ?,
                    clientes_afetados = ?
                WHERE id = ?
            ');
            $stmt->execute([
                $afetados['lotes_count'],
                $afetados['series_count'],
                $afetados['clientes_count'],
                $recallId
            ]);

            $this->pdo->commit();
            return $recallId;
        } catch (Exception $e) {
            $this->pdo->rollBack();
            throw $e;
        }
    }

    /**
     * Identifica produtos/lotes/séries afetados pelo recall
     */
    private function identificarAfetados(array $dados): array {
        $criterioTipo = $dados['criterio_tipo'];
        $criterioValor = $dados['criterio_valor'] ?? null;
        $productId = $dados['product_id'] ?? null;

        $lotes = [];
        $series = [];
        $clientes = [];

        switch ($criterioTipo) {
            case 'lote':
                $stmt = $this->pdo->prepare('
                    SELECT * FROM product_lots
                    WHERE tenant_id = ? AND numero_lote = ?
                    ' . ($productId ? 'AND product_id = ?' : '')
                );
                $params = [$this->tenantId, $criterioValor];
                if ($productId) $params[] = $productId;
                $stmt->execute($params);
                $lotes = $stmt->fetchAll(PDO::FETCH_ASSOC);
                break;

            case 'serie':
                $stmt = $this->pdo->prepare('
                    SELECT * FROM product_serial_numbers
                    WHERE tenant_id = ? AND numero_serie = ?
                    ' . ($productId ? 'AND product_id = ?' : '')
                );
                $params = [$this->tenantId, $criterioValor];
                if ($productId) $params[] = $productId;
                $stmt->execute($params);
                $series = $stmt->fetchAll(PDO::FETCH_ASSOC);
                break;

            case 'data_fabricacao':
                $stmt = $this->pdo->prepare('
                    SELECT * FROM product_lots
                    WHERE tenant_id = ? AND data_fabricacao = ?
                    ' . ($productId ? 'AND product_id = ?' : '')
                );
                $params = [$this->tenantId, $criterioValor];
                if ($productId) $params[] = $productId;
                $stmt->execute($params);
                $lotes = $stmt->fetchAll(PDO::FETCH_ASSOC);
                break;

            case 'fornecedor':
                $stmt = $this->pdo->prepare('
                    SELECT * FROM product_lots
                    WHERE tenant_id = ? AND fornecedor_id = ?
                    ' . ($productId ? 'AND product_id = ?' : '')
                );
                $params = [$this->tenantId, $criterioValor];
                if ($productId) $params[] = $productId;
                $stmt->execute($params);
                $lotes = $stmt->fetchAll(PDO::FETCH_ASSOC);
                break;

            case 'geral':
                if ($productId) {
                    $stmt = $this->pdo->prepare('
                        SELECT * FROM product_lots WHERE tenant_id = ? AND product_id = ?
                    ');
                    $stmt->execute([$this->tenantId, $productId]);
                    $lotes = $stmt->fetchAll(PDO::FETCH_ASSOC);

                    $stmt = $this->pdo->prepare('
                        SELECT * FROM product_serial_numbers WHERE tenant_id = ? AND product_id = ?
                    ');
                    $stmt->execute([$this->tenantId, $productId]);
                    $series = $stmt->fetchAll(PDO::FETCH_ASSOC);
                }
                break;
        }

        // Buscar clientes afetados
        $serieIds = array_column($series, 'id');
        if (!empty($serieIds)) {
            $placeholders = implode(',', array_fill(0, count($serieIds), '?'));
            $stmt = $this->pdo->prepare("
                SELECT DISTINCT cliente_id, nome, email, telefone
                FROM product_serial_numbers
                WHERE id IN ({$placeholders}) AND cliente_id IS NOT NULL
            ");
            $stmt->execute($serieIds);
            $clientes = $stmt->fetchAll(PDO::FETCH_ASSOC);
        }

        return [
            'lotes' => $lotes,
            'series' => $series,
            'clientes' => $clientes,
            'lotes_count' => count($lotes),
            'series_count' => count($series),
            'clientes_count' => count($clientes)
        ];
    }

    /**
     * Atualiza status dos itens afetados
     */
    private function atualizarStatusAfetados(string $criterioTipo, array $afetados): void {
        if (!empty($afetados['lotes'])) {
            $loteIds = array_column($afetados['lotes'], 'id');
            $placeholders = implode(',', array_fill(0, count($loteIds), '?'));
            $stmt = $this->pdo->prepare("
                UPDATE product_lots SET status = 'recall'
                WHERE id IN ({$placeholders}) AND tenant_id = ?
            ");
            $stmt->execute(array_merge($loteIds, [$this->tenantId]));
        }

        if (!empty($afetados['series'])) {
            $serieIds = array_column($afetados['series'], 'id');
            $placeholders = implode(',', array_fill(0, count($serieIds), '?'));
            $stmt = $this->pdo->prepare("
                UPDATE product_serial_numbers SET status = 'recall'
                WHERE id IN ({$placeholders}) AND tenant_id = ?
            ");
            $stmt->execute(array_merge($serieIds, [$this->tenantId]));
        }
    }

    /**
     * Cria registros de clientes afetados
     */
    private function criarClientesAfetados(int $recallId, array $afetados): void {
        foreach ($afetados['clientes'] as $cliente) {
            // Buscar séries do cliente
            $stmt = $this->pdo->prepare('
                SELECT id, product_id, venda_id
                FROM product_serial_numbers
                WHERE cliente_id = ? AND tenant_id = ?
            ');
            $stmt->execute([$cliente['cliente_id'], $this->tenantId]);
            $seriesCliente = $stmt->fetchAll(PDO::FETCH_ASSOC);

            foreach ($seriesCliente as $serie) {
                $stmt = $this->pdo->prepare('
                    INSERT INTO recall_customers (
                        tenant_id, recall_id, cliente_id, nome_cliente, email_cliente, telefone_cliente,
                        product_id, serial_id, venda_id
                    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
                ');
                $stmt->execute([
                    $this->tenantId,
                    $recallId,
                    $cliente['cliente_id'],
                    $cliente['nome'],
                    $cliente['email'],
                    $cliente['telefone'],
                    $serie['product_id'],
                    $serie['id'],
                    $serie['venda_id']
                ]);
            }
        }
    }

    /**
     * Busca vendas relacionadas a um lote
     */
    private function buscarVendasPorLote(int $loteId): array {
        // Buscar movimentações de saída do lote
        $stmt = $this->pdo->prepare('
            SELECT DISTINCT origem_id, origem_numero
            FROM lot_movements
            WHERE lot_id = ? AND origem_tipo = "venda" AND tenant_id = ?
        ');
        $stmt->execute([$loteId, $this->tenantId]);
        $movimentacoes = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $vendas = [];
        foreach ($movimentacoes as $mov) {
            if ($mov['origem_id']) {
                $stmt = $this->pdo->prepare('SELECT * FROM sales_orders WHERE id = ?');
                $stmt->execute([$mov['origem_id']]);
                $venda = $stmt->fetch(PDO::FETCH_ASSOC);
                if ($venda) {
                    $vendas[] = $venda;
                }
            }
        }

        return $vendas;
    }
}

