<?php
namespace Modules\Motopecas\Controllers;

use Gestoreasy\Core\Http\Request;
use Gestoreasy\Core\Http\Response;
use Gestoreasy\Core\Tenant\ConnectionManager;
use Gestoreasy\Core\Audit\AuditLogger;
use Gestoreasy\Core\View\View;
use PDO;
use Exception;

class OrdemServicoController {
    private PDO $pdo;
    
    public function __construct() {
        $this->pdo = ConnectionManager::forTenant();
    }
    
    // ==== Views ====
    public function viewIndex(Request $r): Response {
        return View::renderWithLayout('motopecas/os/index', ['title' => 'Ordens de Serviço']);
    }
    
    public function viewCreate(Request $r): Response {
        return View::renderWithLayout('motopecas/os/create', ['title' => 'Nova Ordem de Serviço']);
    }
    
    public function viewShow(Request $r): Response {
        $id = $r->params['id'] ?? 0;
        return View::renderWithLayout('motopecas/os/show', ['title' => 'Detalhes da OS', 'id' => $id]);
    }
    
    // ==== API ====
    public function list(Request $r): Response {
        try {
            $page = max(1, (int)($r->query['page'] ?? 1));
            $perPage = min(100, max(1, (int)($r->query['per_page'] ?? 20)));
            $offset = ($page - 1) * $perPage;
            
            $where = [];
            $params = [];
            
            if (!empty($r->query['status'])) {
                $where[] = 'status = ?';
                $params[] = $r->query['status'];
            }
            
            if (!empty($r->query['cliente_id'])) {
                $where[] = 'cliente_id = ?';
                $params[] = (int)$r->query['cliente_id'];
            }
            
            if (!empty($r->query['numero'])) {
                $where[] = 'numero LIKE ?';
                $params[] = '%' . $r->query['numero'] . '%';
            }
            
            $whereSql = !empty($where) ? 'WHERE ' . implode(' AND ', $where) : '';
            
            $countStmt = $this->pdo->prepare("SELECT COUNT(*) FROM motopecas_ordem_servico $whereSql");
            $countStmt->execute($params);
            $total = (int)$countStmt->fetchColumn();
            
            $stmt = $this->pdo->prepare("
                SELECT os.*, c.nome as cliente_nome, c.email as cliente_email, c.telefone as cliente_telefone
                FROM motopecas_ordem_servico os
                LEFT JOIN clients c ON os.cliente_id = c.id
                $whereSql
                ORDER BY os.data_abertura DESC
                LIMIT $perPage OFFSET $offset
            ");
            $stmt->execute($params);
            $ordens = $stmt->fetchAll(PDO::FETCH_ASSOC);
            
            return Response::json([
                'data' => $ordens,
                'pagination' => [
                    'page' => $page,
                    'per_page' => $perPage,
                    'total' => $total,
                    'pages' => (int)ceil($total / $perPage)
                ]
            ]);
        } catch (Exception $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function getById(Request $r): Response {
        try {
            $id = (int)($r->params['id'] ?? 0);
            if ($id <= 0) {
                return Response::json(['error' => 'ID inválido'], 400);
            }
            
            $stmt = $this->pdo->prepare("
                SELECT os.*, c.nome as cliente_nome, c.email as cliente_email, c.telefone as cliente_telefone
                FROM motopecas_ordem_servico os
                LEFT JOIN clients c ON os.cliente_id = c.id
                WHERE os.id = ?
            ");
            $stmt->execute([$id]);
            $os = $stmt->fetch(PDO::FETCH_ASSOC);
            
            if (!$os) {
                return Response::json(['error' => 'OS não encontrada'], 404);
            }
            
            // Buscar itens
            $itensStmt = $this->pdo->prepare("
                SELECT i.*, p.codigo as peca_codigo, p.descricao as peca_descricao
                FROM motopecas_os_itens i
                LEFT JOIN motopecas_pecas p ON i.peca_id = p.id
                WHERE i.os_id = ?
                ORDER BY i.ordem, i.id
            ");
            $itensStmt->execute([$id]);
            $os['itens'] = $itensStmt->fetchAll(PDO::FETCH_ASSOC);
            
            return Response::json(['data' => $os]);
        } catch (Exception $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function create(Request $r): Response {
        try {
            $data = $r->body;
            
            // Gerar número da OS
            $numero = $this->gerarNumeroOS();
            
            $this->pdo->beginTransaction();
            
            $stmt = $this->pdo->prepare("
                INSERT INTO motopecas_ordem_servico (
                    numero, cliente_id, moto_marca, moto_modelo, moto_ano, moto_placa, moto_km, moto_chassi,
                    problema_relatado, diagnostico, status, valor_mao_obra, valor_pecas, valor_total,
                    tecnico_id, observacoes
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ");
            
            $valorMaoObra = (float)($data['valor_mao_obra'] ?? 0);
            $valorPecas = (float)($data['valor_pecas'] ?? 0);
            $valorTotal = $valorMaoObra + $valorPecas;
            
            $stmt->execute([
                $numero,
                (int)($data['cliente_id'] ?? 0),
                $data['moto_marca'] ?? null,
                $data['moto_modelo'] ?? null,
                !empty($data['moto_ano']) ? (int)$data['moto_ano'] : null,
                $data['moto_placa'] ?? null,
                !empty($data['moto_km']) ? (float)$data['moto_km'] : null,
                $data['moto_chassi'] ?? null,
                $data['problema_relatado'] ?? null,
                $data['diagnostico'] ?? null,
                $data['status'] ?? 'aberta',
                $valorMaoObra,
                $valorPecas,
                $valorTotal,
                !empty($data['tecnico_id']) ? (int)$data['tecnico_id'] : null,
                $data['observacoes'] ?? null
            ]);
            
            $osId = (int)$this->pdo->lastInsertId();
            
            // Adicionar itens se fornecidos
            if (!empty($data['itens']) && is_array($data['itens'])) {
                $itemStmt = $this->pdo->prepare("
                    INSERT INTO motopecas_os_itens (
                        os_id, tipo, peca_id, descricao, quantidade, valor_unitario, valor_total,
                        desconto_percent, desconto_valor, observacoes, ordem
                    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                ");
                
                foreach ($data['itens'] as $idx => $item) {
                    $quantidade = (float)($item['quantidade'] ?? 1);
                    $valorUnitario = (float)($item['valor_unitario'] ?? 0);
                    $descontoPercent = (float)($item['desconto_percent'] ?? 0);
                    $descontoValor = (float)($item['desconto_valor'] ?? 0);
                    $valorTotal = ($valorUnitario * $quantidade) - $descontoValor - (($valorUnitario * $quantidade) * $descontoPercent / 100);
                    
                    $itemStmt->execute([
                        $osId,
                        $item['tipo'] ?? 'peca',
                        !empty($item['peca_id']) ? (int)$item['peca_id'] : null,
                        $item['descricao'] ?? '',
                        $quantidade,
                        $valorUnitario,
                        $valorTotal,
                        $descontoPercent,
                        $descontoValor,
                        $item['observacoes'] ?? null,
                        $idx
                    ]);
                }
            }
            
            $this->pdo->commit();
            AuditLogger::logCreate('motopecas_ordem_servico', $osId, $data);
            
            return Response::json(['data' => ['id' => $osId, 'numero' => $numero]], 201);
        } catch (Exception $e) {
            $this->pdo->rollBack();
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function update(Request $r): Response {
        try {
            $id = (int)($r->params['id'] ?? 0);
            if ($id <= 0) {
                return Response::json(['error' => 'ID inválido'], 400);
            }
            
            $data = $r->body;
            
            $updateFields = [];
            $params = [];
            
            $fields = [
                'cliente_id', 'moto_marca', 'moto_modelo', 'moto_ano', 'moto_placa', 'moto_km', 'moto_chassi',
                'problema_relatado', 'diagnostico', 'status', 'valor_mao_obra', 'valor_pecas', 'valor_total',
                'tecnico_id', 'observacoes'
            ];
            
            foreach ($fields as $field) {
                if (isset($data[$field])) {
                    $updateFields[] = "$field = ?";
                    if ($field === 'moto_ano' && !empty($data[$field])) {
                        $params[] = (int)$data[$field];
                    } elseif ($field === 'moto_km' && !empty($data[$field])) {
                        $params[] = (float)$data[$field];
                    } elseif (in_array($field, ['valor_mao_obra', 'valor_pecas', 'valor_total'])) {
                        $params[] = (float)$data[$field];
                    } elseif (in_array($field, ['cliente_id', 'tecnico_id']) && !empty($data[$field])) {
                        $params[] = (int)$data[$field];
                    } else {
                        $params[] = $data[$field];
                    }
                }
            }
            
            if (empty($updateFields)) {
                return Response::json(['error' => 'Nenhum campo para atualizar'], 400);
            }
            
            $updateFields[] = 'updated_at = CURRENT_TIMESTAMP';
            $params[] = $id;
            
            $sql = "UPDATE motopecas_ordem_servico SET " . implode(', ', $updateFields) . " WHERE id = ?";
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute($params);
            
            AuditLogger::logUpdate('motopecas_ordem_servico', $id, [], $data);
            
            return Response::json(['data' => ['id' => $id, 'updated' => true]]);
        } catch (Exception $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function finalizar(Request $r): Response {
        try {
            $id = (int)($r->params['id'] ?? 0);
            if ($id <= 0) {
                return Response::json(['error' => 'ID inválido'], 400);
            }
            
            // Recalcular totais
            $itensStmt = $this->pdo->prepare("
                SELECT SUM(CASE WHEN tipo = 'mao_obra' THEN valor_total ELSE 0 END) as mao_obra,
                       SUM(CASE WHEN tipo IN ('peca', 'servico') THEN valor_total ELSE 0 END) as pecas
                FROM motopecas_os_itens
                WHERE os_id = ?
            ");
            $itensStmt->execute([$id]);
            $totais = $itensStmt->fetch(PDO::FETCH_ASSOC);
            
            $valorMaoObra = (float)($totais['mao_obra'] ?? 0);
            $valorPecas = (float)($totais['pecas'] ?? 0);
            $valorTotal = $valorMaoObra + $valorPecas;
            
            $stmt = $this->pdo->prepare("
                UPDATE motopecas_ordem_servico SET
                    status = 'finalizada',
                    valor_mao_obra = ?,
                    valor_pecas = ?,
                    valor_total = ?,
                    data_finalizacao = CURRENT_TIMESTAMP,
                    updated_at = CURRENT_TIMESTAMP
                WHERE id = ?
            ");
            $stmt->execute([$valorMaoObra, $valorPecas, $valorTotal, $id]);
            
            // Registrar no histórico
            $osStmt = $this->pdo->prepare("
                SELECT cliente_id, moto_marca, moto_modelo, moto_placa, valor_total
                FROM motopecas_ordem_servico
                WHERE id = ?
            ");
            $osStmt->execute([$id]);
            $os = $osStmt->fetch(PDO::FETCH_ASSOC);
            
            if ($os) {
                $histStmt = $this->pdo->prepare("
                    INSERT INTO motopecas_historico_servicos (
                        cliente_id, os_id, moto_marca, moto_modelo, moto_placa,
                        servico_realizado, valor_total, data_servico
                    ) VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
                ");
                $histStmt->execute([
                    $os['cliente_id'],
                    $id,
                    $os['moto_marca'],
                    $os['moto_modelo'],
                    $os['moto_placa'],
                    'Ordem de Serviço #' . $id,
                    $os['valor_total']
                ]);
            }
            
            AuditLogger::logUpdate('motopecas_ordem_servico', $id, [], ['status' => 'finalizada']);
            
            return Response::json(['data' => ['id' => $id, 'finalizada' => true]]);
        } catch (Exception $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function cancelar(Request $r): Response {
        try {
            $id = (int)($r->params['id'] ?? 0);
            if ($id <= 0) {
                return Response::json(['error' => 'ID inválido'], 400);
            }
            
            $stmt = $this->pdo->prepare("
                UPDATE motopecas_ordem_servico SET
                    status = 'cancelada',
                    updated_at = CURRENT_TIMESTAMP
                WHERE id = ?
            ");
            $stmt->execute([$id]);
            
            AuditLogger::logUpdate('motopecas_ordem_servico', $id, [], ['status' => 'cancelada']);
            
            return Response::json(['data' => ['id' => $id, 'cancelada' => true]]);
        } catch (Exception $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function addItem(Request $r): Response {
        try {
            $osId = (int)($r->params['id'] ?? 0);
            if ($osId <= 0) {
                return Response::json(['error' => 'ID inválido'], 400);
            }
            
            $data = $r->body;
            
            // Buscar última ordem
            $ordemStmt = $this->pdo->prepare("SELECT MAX(ordem) as max_ordem FROM motopecas_os_itens WHERE os_id = ?");
            $ordemStmt->execute([$osId]);
            $ordem = (int)($ordemStmt->fetchColumn() ?? 0) + 1;
            
            $quantidade = (float)($data['quantidade'] ?? 1);
            $valorUnitario = (float)($data['valor_unitario'] ?? 0);
            $descontoPercent = (float)($data['desconto_percent'] ?? 0);
            $descontoValor = (float)($data['desconto_valor'] ?? 0);
            $valorTotal = ($valorUnitario * $quantidade) - $descontoValor - (($valorUnitario * $quantidade) * $descontoPercent / 100);
            
            $stmt = $this->pdo->prepare("
                INSERT INTO motopecas_os_itens (
                    os_id, tipo, peca_id, descricao, quantidade, valor_unitario, valor_total,
                    desconto_percent, desconto_valor, observacoes, ordem
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ");
            
            $stmt->execute([
                $osId,
                $data['tipo'] ?? 'peca',
                !empty($data['peca_id']) ? (int)$data['peca_id'] : null,
                $data['descricao'] ?? '',
                $quantidade,
                $valorUnitario,
                $valorTotal,
                $descontoPercent,
                $descontoValor,
                $data['observacoes'] ?? null,
                $ordem
            ]);
            
            $itemId = (int)$this->pdo->lastInsertId();
            
            // Atualizar totais da OS
            $this->recalcularTotaisOS($osId);
            
            return Response::json(['data' => ['id' => $itemId]], 201);
        } catch (Exception $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function updateItem(Request $r): Response {
        try {
            $osId = (int)($r->params['id'] ?? 0);
            $itemId = (int)($r->params['itemId'] ?? 0);
            
            if ($osId <= 0 || $itemId <= 0) {
                return Response::json(['error' => 'ID inválido'], 400);
            }
            
            $data = $r->body;
            
            $updateFields = [];
            $params = [];
            
            if (isset($data['quantidade'])) {
                $updateFields[] = 'quantidade = ?';
                $params[] = (float)$data['quantidade'];
            }
            
            if (isset($data['valor_unitario'])) {
                $updateFields[] = 'valor_unitario = ?';
                $params[] = (float)$data['valor_unitario'];
            }
            
            if (isset($data['desconto_percent'])) {
                $updateFields[] = 'desconto_percent = ?';
                $params[] = (float)$data['desconto_percent'];
            }
            
            if (isset($data['desconto_valor'])) {
                $updateFields[] = 'desconto_valor = ?';
                $params[] = (float)$data['desconto_valor'];
            }
            
            if (empty($updateFields)) {
                return Response::json(['error' => 'Nenhum campo para atualizar'], 400);
            }
            
            // Recalcular valor_total
            $itemStmt = $this->pdo->prepare("SELECT quantidade, valor_unitario, desconto_percent, desconto_valor FROM motopecas_os_itens WHERE id = ?");
            $itemStmt->execute([$itemId]);
            $item = $itemStmt->fetch(PDO::FETCH_ASSOC);
            
            $quantidade = isset($data['quantidade']) ? (float)$data['quantidade'] : (float)$item['quantidade'];
            $valorUnitario = isset($data['valor_unitario']) ? (float)$data['valor_unitario'] : (float)$item['valor_unitario'];
            $descontoPercent = isset($data['desconto_percent']) ? (float)$data['desconto_percent'] : (float)$item['desconto_percent'];
            $descontoValor = isset($data['desconto_valor']) ? (float)$data['desconto_valor'] : (float)$item['desconto_valor'];
            $valorTotal = ($valorUnitario * $quantidade) - $descontoValor - (($valorUnitario * $quantidade) * $descontoPercent / 100);
            
            $updateFields[] = 'valor_total = ?';
            $params[] = $valorTotal;
            $params[] = $itemId;
            $params[] = $osId;
            
            $sql = "UPDATE motopecas_os_itens SET " . implode(', ', $updateFields) . " WHERE id = ? AND os_id = ?";
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute($params);
            
            // Atualizar totais da OS
            $this->recalcularTotaisOS($osId);
            
            return Response::json(['data' => ['id' => $itemId, 'updated' => true]]);
        } catch (Exception $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function removeItem(Request $r): Response {
        try {
            $osId = (int)($r->params['id'] ?? 0);
            $itemId = (int)($r->params['itemId'] ?? 0);
            
            if ($osId <= 0 || $itemId <= 0) {
                return Response::json(['error' => 'ID inválido'], 400);
            }
            
            $stmt = $this->pdo->prepare("DELETE FROM motopecas_os_itens WHERE id = ? AND os_id = ?");
            $stmt->execute([$itemId, $osId]);
            
            if ($stmt->rowCount() === 0) {
                return Response::json(['error' => 'Item não encontrado'], 404);
            }
            
            // Atualizar totais da OS
            $this->recalcularTotaisOS($osId);
            
            return Response::json(['data' => ['id' => $itemId, 'deleted' => true]]);
        } catch (Exception $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    private function gerarNumeroOS(): string {
        $stmt = $this->pdo->query("SELECT MAX(CAST(SUBSTRING(numero, 4) AS UNSIGNED)) as max_num FROM motopecas_ordem_servico WHERE numero LIKE 'OS-%'");
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        $nextNum = (int)($result['max_num'] ?? 0) + 1;
        return 'OS-' . str_pad((string)$nextNum, 6, '0', STR_PAD_LEFT);
    }
    
    private function recalcularTotaisOS(int $osId): void {
        $itensStmt = $this->pdo->prepare("
            SELECT SUM(CASE WHEN tipo = 'mao_obra' THEN valor_total ELSE 0 END) as mao_obra,
                   SUM(CASE WHEN tipo IN ('peca', 'servico') THEN valor_total ELSE 0 END) as pecas
            FROM motopecas_os_itens
            WHERE os_id = ?
        ");
        $itensStmt->execute([$osId]);
        $totais = $itensStmt->fetch(PDO::FETCH_ASSOC);
        
        $valorMaoObra = (float)($totais['mao_obra'] ?? 0);
        $valorPecas = (float)($totais['pecas'] ?? 0);
        $valorTotal = $valorMaoObra + $valorPecas;
        
        $updateStmt = $this->pdo->prepare("
            UPDATE motopecas_ordem_servico SET
                valor_mao_obra = ?,
                valor_pecas = ?,
                valor_total = ?,
                updated_at = CURRENT_TIMESTAMP
            WHERE id = ?
        ");
        $updateStmt->execute([$valorMaoObra, $valorPecas, $valorTotal, $osId]);
    }
}

