<?php
namespace Modules\GestorY\Services;

use Gestoreasy\Core\Tenant\ConnectionManager;
use Gestoreasy\Core\Tenant\TenantContext;
use PDO;
use Exception;

/**
 * Serviço para geração de ordens de compra a partir de peças pesquisadas
 */
class PurchaseOrderService {
    private PDO $pdo;
    private string $tenantId;
    
    public function __construct() {
        $this->pdo = ConnectionManager::forTenant();
        $this->tenantId = TenantContext::getTenantId();
    }
    
    /**
     * Cria ordem de compra com peças pesquisadas
     * 
     * @param array $pecas Array de peças com código, quantidade, preco, etc.
     * @param int|null $fornecedorId ID do fornecedor (opcional)
     * @param array $dadosAdicionais Dados adicionais da ordem
     * @return array Dados da ordem criada
     */
    public function criarOrdemCompra(array $pecas, ?int $fornecedorId = null, array $dadosAdicionais = []): array {
        try {
            $this->pdo->beginTransaction();
            
            // Gerar número da ordem
            $numero = $this->gerarNumeroOrdem();
            
            // Calcular totais
            $valorTotal = 0;
            foreach ($pecas as $peca) {
                $quantidade = (float)($peca['quantidade'] ?? 1);
                $preco = (float)($peca['preco'] ?? 0);
                $valorTotal += $quantidade * $preco;
            }
            
            // Verificar se tabela purchase_orders existe e tem estrutura correta
            $tabelaExiste = $this->verificarTabelaExiste('purchase_orders');
            $usarTabelaCompras = false;
            
            if ($tabelaExiste) {
                // Verificar se a tabela tem os campos necessários
                $camposExistentes = $this->verificarCamposTabela('purchase_orders', ['supplier_id', 'status', 'observacoes']);
                if ($camposExistentes) {
                    $usarTabelaCompras = true;
                }
            }
            
            if ($usarTabelaCompras) {
                // Criar ordem na tabela de compras (estrutura real)
                // Verificar se supplier_id é obrigatório
                if ($fornecedorId === null || $fornecedorId === 0) {
                    // Se não tem fornecedor, tentar obter ou criar fornecedor genérico
                    $fornecedorId = $this->obterOuCriarFornecedorGenerico();
                }
                
                // Se ainda não tem fornecedor válido, usar fallback para gestory_ordens_compra
                if ($fornecedorId === null || $fornecedorId === 0) {
                    $usarTabelaCompras = false;
                } else {
                    try {
                        $stmt = $this->pdo->prepare("
                            INSERT INTO purchase_orders (
                                supplier_id, status, situacao, observacoes, created_at
                            ) VALUES (?, ?, ?, ?, NOW())
                        ");
                        
                        $stmt->execute([
                            $fornecedorId,
                            $dadosAdicionais['status'] ?? 'draft',
                            $dadosAdicionais['situacao'] ?? 'aberto',
                            ($dadosAdicionais['observacoes'] ?? '') . "\nOrdem criada via Gestor-Y\nValor Total: R$ " . number_format($valorTotal, 2, ',', '.')
                        ]);
                        
                        $ordemId = (int)$this->pdo->lastInsertId();
                        
                        // Adicionar itens
                        $itemStmt = $this->pdo->prepare("
                            INSERT INTO purchase_order_items (
                                order_id, product_id, product_description, quantity, unit_price
                            ) VALUES (?, ?, ?, ?, ?)
                        ");
                        
                        foreach ($pecas as $peca) {
                            $quantidade = (float)($peca['quantidade'] ?? 1);
                            $preco = (float)($peca['preco'] ?? 0);
                            
                            $itemStmt->execute([
                                $ordemId,
                                $peca['product_id'] ?? null,
                                ($peca['descricao'] ?? $peca['nome'] ?? '') . ' (' . ($peca['codigo'] ?? '') . ')',
                                $quantidade,
                                $preco
                            ]);
                        }
                    } catch (Exception $e) {
                        // Se falhar, usar fallback
                        error_log("Erro ao criar ordem na tabela purchase_orders: " . $e->getMessage());
                        $usarTabelaCompras = false;
                    }
                }
            }
            
            if (!$usarTabelaCompras) {
                // Se tabela não existe, criar ordem na tabela gestory_ordens_compra
                $this->criarTabelaOrdensCompra();
                
                $stmt = $this->pdo->prepare("
                    INSERT INTO gestory_ordens_compra (
                        numero, fornecedor_id, status, valor_total, data_emissao, 
                        data_entrega_prevista, observacoes, tenant_id, created_at
                    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW())
                ");
                
                $stmt->execute([
                    $numero,
                    $fornecedorId,
                    $dadosAdicionais['status'] ?? 'aberta',
                    $valorTotal,
                    $dadosAdicionais['data_emissao'] ?? date('Y-m-d'),
                    $dadosAdicionais['data_entrega_prevista'] ?? null,
                    $dadosAdicionais['observacoes'] ?? null,
                    $this->tenantId
                ]);
                
                $ordemId = (int)$this->pdo->lastInsertId();
                
                // Adicionar itens
                $itemStmt = $this->pdo->prepare("
                    INSERT INTO gestory_ordens_compra_itens (
                        ordem_compra_id, codigo, descricao, quantidade, 
                        preco_unitario, valor_total, observacoes, imagem_url
                    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
                ");
                
                foreach ($pecas as $peca) {
                    $quantidade = (float)($peca['quantidade'] ?? 1);
                    $preco = (float)($peca['preco'] ?? 0);
                    $valorItem = $quantidade * $preco;
                    
                    $itemStmt->execute([
                        $ordemId,
                        $peca['codigo'] ?? '',
                        $peca['descricao'] ?? $peca['nome'] ?? '',
                        $quantidade,
                        $preco,
                        $valorItem,
                        $peca['observacoes'] ?? null,
                        $peca['imagem_url'] ?? $peca['imagem']['url'] ?? null
                    ]);
                }
            }
            
            $this->pdo->commit();
            
            return [
                'id' => $ordemId,
                'numero' => $numero,
                'valor_total' => $valorTotal,
                'quantidade_itens' => count($pecas),
                'status' => $dadosAdicionais['status'] ?? 'aberta'
            ];
            
        } catch (Exception $e) {
            $this->pdo->rollBack();
            throw new Exception("Erro ao criar ordem de compra: " . $e->getMessage());
        }
    }
    
    /**
     * Gera número único para ordem de compra
     */
    private function gerarNumeroOrdem(): string {
        // Tentar buscar última ordem na tabela gestory (mais confiável)
        $this->criarTabelaOrdensCompra();
        
        try {
            $stmt = $this->pdo->prepare("
                SELECT MAX(CAST(SUBSTRING(numero, 4) AS UNSIGNED)) as max_num 
                FROM gestory_ordens_compra 
                WHERE numero LIKE 'OC-%' AND tenant_id = ?
            ");
            $stmt->execute([$this->tenantId]);
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            $nextNum = (int)($result['max_num'] ?? 0) + 1;
        } catch (Exception $e) {
            // Se falhar, usar timestamp
            $nextNum = (int)(time() % 1000000);
        }
        
        return 'OC-' . str_pad((string)$nextNum, 6, '0', STR_PAD_LEFT);
    }
    
    /**
     * Verifica se uma tabela existe
     */
    private function verificarTabelaExiste(string $tabela): bool {
        try {
            $stmt = $this->pdo->prepare("
                SELECT COUNT(*) as total 
                FROM information_schema.tables 
                WHERE table_schema = DATABASE() 
                AND table_name = ?
            ");
            $stmt->execute([$tabela]);
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            return (int)($result['total'] ?? 0) > 0;
        } catch (Exception $e) {
            return false;
        }
    }
    
    /**
     * Verifica se campos existem em uma tabela
     */
    private function verificarCamposTabela(string $tabela, array $campos): bool {
        try {
            $placeholders = str_repeat('?,', count($campos));
            $placeholders = rtrim($placeholders, ',');
            $stmt = $this->pdo->prepare("
                SELECT COUNT(*) as total 
                FROM information_schema.columns 
                WHERE table_schema = DATABASE() 
                AND table_name = ? 
                AND column_name IN ($placeholders)
            ");
            $params = array_merge([$tabela], $campos);
            $stmt->execute($params);
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            return (int)($result['total'] ?? 0) === count($campos);
        } catch (Exception $e) {
            return false;
        }
    }
    
    /**
     * Obtém ou cria fornecedor genérico
     */
    private function obterOuCriarFornecedorGenerico(): int {
        try {
            // Verificar se tabela suppliers existe
            if (!$this->verificarTabelaExiste('suppliers')) {
                // Se não existe, retornar 0 (será tratado no fallback)
                throw new Exception('Tabela suppliers não existe');
            }
            
            // Verificar campos da tabela (pode ser 'nome' ou 'name')
            $camposNome = $this->verificarCamposTabela('suppliers', ['nome']) ? 'nome' : 
                         ($this->verificarCamposTabela('suppliers', ['name']) ? 'name' : null);
            
            if (!$camposNome) {
                throw new Exception('Tabela suppliers não possui campo nome/name');
            }
            
            // Buscar fornecedor genérico "Yamaha" ou criar
            $stmt = $this->pdo->prepare("SELECT id FROM suppliers WHERE $camposNome LIKE ? LIMIT 1");
            $stmt->execute(['%Yamaha%']);
            $fornecedor = $stmt->fetch(PDO::FETCH_ASSOC);
            
            if ($fornecedor) {
                return (int)$fornecedor['id'];
            }
            
            // Criar fornecedor genérico (verificar campos disponíveis)
            $temContato = $this->verificarCamposTabela('suppliers', ['contato']);
            $temEmail = $this->verificarCamposTabela('suppliers', ['email']);
            
            if ($camposNome === 'nome') {
                // Estrutura do módulo Compras (nome, cnpj, email, contato)
                $campos = ['nome'];
                $valores = ['Yamaha - Gestor-Y'];
                
                if ($temEmail) {
                    $campos[] = 'email';
                    $valores[] = '';
                }
                if ($temContato) {
                    $campos[] = 'contato';
                    $valores[] = '';
                }
                
                $sql = "INSERT INTO suppliers (" . implode(', ', $campos) . ", created_at) VALUES (" . 
                       str_repeat('?,', count($campos)) . " NOW())";
            } else {
                // Estrutura alternativa (name, contact, email)
                $campos = ['name'];
                $valores = ['Yamaha - Gestor-Y'];
                
                if ($temEmail) {
                    $campos[] = 'email';
                    $valores[] = '';
                }
                if ($temContato) {
                    $campos[] = 'contact';
                    $valores[] = '';
                }
                
                $sql = "INSERT INTO suppliers (" . implode(', ', $campos) . ", created_at) VALUES (" . 
                       str_repeat('?,', count($campos)) . " NOW())";
            }
            
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute($valores);
            return (int)$this->pdo->lastInsertId();
            
        } catch (Exception $e) {
            // Se não conseguir, retornar 0 (será tratado no fallback)
            error_log("Erro ao obter/criar fornecedor genérico: " . $e->getMessage());
            return 0;
        }
    }
    
    /**
     * Cria tabela de ordens de compra do Gestor-Y
     */
    private function criarTabelaOrdensCompra(): void {
        try {
            $this->pdo->exec("
                CREATE TABLE IF NOT EXISTS gestory_ordens_compra (
                    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                    numero VARCHAR(50) NOT NULL,
                    fornecedor_id INT UNSIGNED NULL,
                    status ENUM('aberta', 'enviada', 'aprovada', 'recebida', 'cancelada') NOT NULL DEFAULT 'aberta',
                    valor_total DECIMAL(12,2) NOT NULL DEFAULT 0.00,
                    data_emissao DATE NOT NULL,
                    data_entrega_prevista DATE NULL,
                    observacoes TEXT NULL,
                    tenant_id VARCHAR(100) NOT NULL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                    INDEX idx_numero (numero),
                    INDEX idx_fornecedor_id (fornecedor_id),
                    INDEX idx_status (status),
                    INDEX idx_tenant_id (tenant_id),
                    UNIQUE KEY uk_numero_tenant (numero, tenant_id)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
            ");
            
            $this->pdo->exec("
                CREATE TABLE IF NOT EXISTS gestory_ordens_compra_itens (
                    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                    ordem_compra_id INT UNSIGNED NOT NULL,
                    codigo VARCHAR(100) NOT NULL,
                    descricao VARCHAR(255) NOT NULL,
                    quantidade DECIMAL(12,3) NOT NULL DEFAULT 1.00,
                    preco_unitario DECIMAL(12,2) NOT NULL DEFAULT 0.00,
                    valor_total DECIMAL(12,2) NOT NULL DEFAULT 0.00,
                    observacoes TEXT NULL,
                    imagem_url VARCHAR(500) NULL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    INDEX idx_ordem_compra_id (ordem_compra_id),
                    INDEX idx_codigo (codigo),
                    FOREIGN KEY (ordem_compra_id) REFERENCES gestory_ordens_compra(id) ON DELETE CASCADE
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
            ");
        } catch (Exception $e) {
            // Tabela pode já existir
        }
    }
    
    /**
     * Lista ordens de compra
     */
    public function listarOrdensCompra(array $filtros = []): array {
        $tabelaExiste = $this->verificarTabelaExiste('purchase_orders');
        
        if ($tabelaExiste && $this->verificarCamposTabela('purchase_orders', ['supplier_id', 'status'])) {
            $sql = "SELECT * FROM purchase_orders WHERE 1=1";
            $params = [];
            
            if (!empty($filtros['status'])) {
                $sql .= " AND status = ?";
                $params[] = $filtros['status'];
            }
            
            if (!empty($filtros['fornecedor_id'])) {
                $sql .= " AND supplier_id = ?";
                $params[] = (int)$filtros['fornecedor_id'];
            }
            
            $sql .= " ORDER BY created_at DESC";
            
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute($params);
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } else {
            $sql = "SELECT * FROM gestory_ordens_compra WHERE tenant_id = ?";
            $params = [$this->tenantId];
            
            if (!empty($filtros['status'])) {
                $sql .= " AND status = ?";
                $params[] = $filtros['status'];
            }
            
            $sql .= " ORDER BY created_at DESC";
            
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute($params);
            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        }
    }
    
    /**
     * Obtém detalhes de uma ordem de compra
     */
    public function getOrdemCompra(int $ordemId): ?array {
        $tabelaExiste = $this->verificarTabelaExiste('purchase_orders');
        
        if ($tabelaExiste && $this->verificarCamposTabela('purchase_orders', ['supplier_id', 'status'])) {
            $stmt = $this->pdo->prepare("SELECT * FROM purchase_orders WHERE id = ?");
            $stmt->execute([$ordemId]);
            $ordem = $stmt->fetch(PDO::FETCH_ASSOC);
            
            if ($ordem) {
                // Verificar qual campo de relacionamento usar
                $campoRelacao = $this->verificarCamposTabela('purchase_order_items', ['order_id']) ? 'order_id' : 'purchase_order_id';
                $itemStmt = $this->pdo->prepare("SELECT * FROM purchase_order_items WHERE $campoRelacao = ?");
                $itemStmt->execute([$ordemId]);
                $ordem['itens'] = $itemStmt->fetchAll(PDO::FETCH_ASSOC);
            }
            
            return $ordem ?: null;
        } else {
            $stmt = $this->pdo->prepare("SELECT * FROM gestory_ordens_compra WHERE id = ? AND tenant_id = ?");
            $stmt->execute([$ordemId, $this->tenantId]);
            $ordem = $stmt->fetch(PDO::FETCH_ASSOC);
            
            if ($ordem) {
                $itemStmt = $this->pdo->prepare("SELECT * FROM gestory_ordens_compra_itens WHERE ordem_compra_id = ?");
                $itemStmt->execute([$ordemId]);
                $ordem['itens'] = $itemStmt->fetchAll(PDO::FETCH_ASSOC);
            }
            
            return $ordem ?: null;
        }
    }
}

