<?php
class PaymentCenter
{
    public static function banks(bool $onlyActive = false): array
    {
        Database::migrate();
        $sql = 'SELECT * FROM payment_banks' . ($onlyActive ? ' WHERE is_active=1' : '') . ' ORDER BY is_active DESC, name ASC';
        return Database::pdo()->query($sql)->fetchAll();
    }

    public static function saveBank(array $data, array $imageFile = []): array
    {
        Database::migrate();
        $id = (int)($data['bank_id'] ?? 0);
        $name = trim($data['name'] ?? '');
        $description = trim($data['description'] ?? '');
        $accessUrl = trim($data['access_url'] ?? '');
        $pixCode = trim($data['pix_code'] ?? '');
        if ($name === '') return ['ok'=>false,'message'=>'Informe o nome do banco ou forma de pagamento.'];
        if ($accessUrl !== '' && !is_valid_http_url($accessUrl)) return ['ok'=>false,'message'=>'O link do banco precisa começar com http ou https.'];
        $existing = null;
        if ($id > 0) {
            $stmt = Database::pdo()->prepare('SELECT * FROM payment_banks WHERE id=?');
            $stmt->execute([$id]);
            $existing = $stmt->fetch();
            if (!$existing) return ['ok'=>false,'message'=>'Banco não encontrado.'];
        }
        $imagePath = $existing['image_path'] ?? null;
        if (!empty($imageFile['tmp_name'])) {
            $saved = PortalMedia::saveImage($imageFile, 'payment_banks');
            if (!$saved['ok']) return $saved;
            PortalMedia::delete($imagePath);
            $imagePath = $saved['path'];
        }
        if ($id > 0) {
            $stmt = Database::pdo()->prepare('UPDATE payment_banks SET name=?,description=?,access_url=?,pix_code=?,image_path=? WHERE id=?');
            $stmt->execute([$name,$description,$accessUrl ?: null,$pixCode ?: null,$imagePath,$id]);
            return ['ok'=>true,'message'=>'Banco atualizado.'];
        }
        $stmt = Database::pdo()->prepare('INSERT INTO payment_banks (name,description,access_url,pix_code,image_path,is_active,created_at) VALUES (?,?,?,?,?,1,?)');
        $stmt->execute([$name,$description,$accessUrl ?: null,$pixCode ?: null,$imagePath,date('Y-m-d H:i:s')]);
        return ['ok'=>true,'message'=>'Banco cadastrado.'];
    }

    public static function toggleBank(int $id): bool
    {
        Database::migrate();
        $stmt = Database::pdo()->prepare('UPDATE payment_banks SET is_active=CASE WHEN is_active=1 THEN 0 ELSE 1 END WHERE id=?');
        $stmt->execute([$id]);
        return $stmt->rowCount() > 0;
    }

    public static function deleteBank(int $id): array
    {
        Database::migrate();
        $check = Database::pdo()->prepare('SELECT COUNT(*) FROM payment_charges WHERE bank_id=?');
        $check->execute([$id]);
        if ((int)$check->fetchColumn() > 0) return ['ok'=>false,'message'=>'Este banco já está ligado a cobranças. Desative-o em vez de apagar.'];
        $stmt = Database::pdo()->prepare('SELECT image_path FROM payment_banks WHERE id=?');
        $stmt->execute([$id]);
        $row = $stmt->fetch();
        if (!$row) return ['ok'=>false,'message'=>'Banco não encontrado.'];
        $del = Database::pdo()->prepare('DELETE FROM payment_banks WHERE id=?');
        $del->execute([$id]);
        PortalMedia::delete($row['image_path'] ?? '');
        return ['ok'=>true,'message'=>'Banco apagado.'];
    }

    public static function saveCharge(array $data): array
    {
        Database::migrate();
        $id = (int)($data['charge_id'] ?? 0);
        $bankId = (int)($data['bank_id'] ?? 0);
        $recipientTypeRaw = trim((string)($data['recipient_type'] ?? ''));
        $recipientId = (int)($data['recipient_id'] ?? 0);
        $recipientKey = trim((string)($data['recipient_key'] ?? ''));
        if (($recipientTypeRaw === '' || $recipientId <= 0) && preg_match('/^(student|professional|beginner):(\d+)$/', $recipientKey, $match)) {
            $recipientTypeRaw = $match[1];
            $recipientId = (int)$match[2];
        }
        $recipientType = normalize_internal_actor_type($recipientTypeRaw !== '' ? $recipientTypeRaw : 'student');
        $title = trim($data['title'] ?? '');
        $amount = max(0, parse_money_br($data['amount'] ?? 0));
        $dueDate = trim($data['due_date'] ?? '');
        $notes = trim($data['notes'] ?? '');
        $status = trim($data['status'] ?? 'pending');
        if (!in_array($recipientType, ['student','beginner'], true)) return ['ok'=>false,'message'=>'Tipo de destinatário inválido.'];
        if ($recipientId <= 0 || $bankId <= 0) return ['ok'=>false,'message'=>'Selecione o destinatário e o banco.'];
        $recipient = Communication::actorByTypeAndId($recipientType, $recipientId);
        if (!$recipient || ($recipient['actor_type'] ?? '') !== $recipientType) return ['ok'=>false,'message'=>'O destinatário selecionado não foi encontrado.'];
        $bankCheck = Database::pdo()->prepare('SELECT COUNT(*) FROM payment_banks WHERE id=? AND is_active=1');
        $bankCheck->execute([$bankId]);
        if ((int)$bankCheck->fetchColumn() <= 0) return ['ok'=>false,'message'=>'O banco selecionado não está ativo.'];
        if ($title === '') return ['ok'=>false,'message'=>'Informe o título da cobrança.'];
        if ($dueDate !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $dueDate)) return ['ok'=>false,'message'=>'Data de vencimento inválida.'];
        if (!in_array($status, ['pending','paid','canceled'], true)) $status = 'pending';
        $active = array_key_exists('is_active', $data) ? (!empty($data['is_active']) ? 1 : 0) : 1;
        $paidAt = $status === 'paid' ? date('Y-m-d H:i:s') : null;
        if ($id > 0) {
            $stmt = Database::pdo()->prepare('UPDATE payment_charges SET bank_id=?,recipient_type=?,recipient_id=?,title=?,amount=?,due_date=?,notes=?,status=?,is_active=?,paid_at=? WHERE id=?');
            $stmt->execute([$bankId,$recipientType,$recipientId,$title,$amount,$dueDate ?: null,$notes,$status,$active,$paidAt,$id]);
            if ($status === 'paid') PaymentReceipt::ensureForCharge($id); else PaymentReceipt::removeForCharge($id);
            return ['ok'=>true,'message'=>'Cobrança atualizada.'];
        }
        $stmt = Database::pdo()->prepare('INSERT INTO payment_charges (bank_id,recipient_type,recipient_id,title,amount,due_date,notes,status,is_active,created_at,paid_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)');
        $stmt->execute([$bankId,$recipientType,$recipientId,$title,$amount,$dueDate ?: null,$notes,$status,$active,date('Y-m-d H:i:s'),$paidAt]);
        $newId = (int)Database::pdo()->lastInsertId();
        if ($status === 'paid' && $newId > 0) PaymentReceipt::ensureForCharge($newId);
        return ['ok'=>true,'message'=>'Cobrança enviada ao painel do destinatário.'];
    }

    public static function charges(): array
    {
        Database::migrate();
        PaymentReceipt::ensureTable();
        $rows = Database::pdo()->query('SELECT c.*, b.name AS bank_name, b.image_path AS bank_image, b.access_url, b.pix_code, r.receipt_code, r.id AS receipt_id FROM payment_charges c INNER JOIN payment_banks b ON b.id=c.bank_id LEFT JOIN payment_receipts r ON r.charge_id=c.id ORDER BY c.id DESC')->fetchAll();
        foreach ($rows as &$row) {
            if (($row['status'] ?? '') === 'paid' && empty($row['receipt_code'])) {
                $receipt = PaymentReceipt::ensureForCharge((int)$row['id']);
                if ($receipt) { $row['receipt_code'] = $receipt['receipt_code']; $row['receipt_id'] = $receipt['id']; }
            }
            $actor = Communication::actorByTypeAndId($row['recipient_type'], (int)$row['recipient_id']);
            $row['recipient_name'] = $actor['name'] ?? 'Cadastro removido';
            $row['recipient_whatsapp'] = $actor['whatsapp'] ?? '';
        }
        unset($row);
        return $rows;
    }

    public static function forActor(string $actorType, int $actorId): array
    {
        Database::migrate();
        $actorType = normalize_internal_actor_type($actorType);
        if ($actorType === 'professional') return [];
        $aliases = match ($actorType) {
            'beginner' => ['beginner', 'formacao', 'formação'],
            default => ['student', 'aluno', 'alunos'],
        };
        $placeholders = implode(',', array_fill(0, count($aliases), '?'));
        PaymentReceipt::ensureTable();
        $stmt = Database::pdo()->prepare("SELECT c.*, b.name AS bank_name, b.description AS bank_description, b.image_path AS bank_image, b.access_url, b.pix_code, r.receipt_code, r.id AS receipt_id
            FROM payment_charges c INNER JOIN payment_banks b ON b.id=c.bank_id LEFT JOIN payment_receipts r ON r.charge_id=c.id
            WHERE LOWER(TRIM(c.recipient_type)) IN ({$placeholders}) AND c.recipient_id=? AND c.is_active=1 AND c.status!='canceled'
            ORDER BY CASE c.status WHEN 'pending' THEN 1 ELSE 2 END, c.due_date ASC, c.id DESC");
        $stmt->execute(array_merge($aliases, [$actorId]));
        $rows = $stmt->fetchAll();
        foreach ($rows as &$row) {
            if (($row['status'] ?? '') === 'paid' && empty($row['receipt_code'])) {
                $receipt = PaymentReceipt::ensureForCharge((int)$row['id']);
                if ($receipt) { $row['receipt_code'] = $receipt['receipt_code']; $row['receipt_id'] = $receipt['id']; }
            }
        }
        unset($row);
        return $rows;
    }


    public static function pendingForActor(string $actorType, int $actorId): array
    {
        return array_values(array_filter(self::forActor($actorType, $actorId), static fn(array $row): bool => ($row['status'] ?? '') === 'pending'));
    }

    public static function updateChargeStatus(int $id, string $status): array
    {
        Database::migrate();
        if (!in_array($status, ['pending','paid'], true)) return ['ok'=>false,'message'=>'Status inválido.'];
        $paidAt = $status === 'paid' ? date('Y-m-d H:i:s') : null;
        $stmt = Database::pdo()->prepare('UPDATE payment_charges SET status=?,paid_at=? WHERE id=?');
        $stmt->execute([$status,$paidAt,$id]);
        $exists = Database::pdo()->prepare('SELECT COUNT(*) FROM payment_charges WHERE id=?');
        $exists->execute([$id]);
        if ((int)$exists->fetchColumn() <= 0) return ['ok'=>false,'message'=>'Cobrança não encontrada.'];
        if ($status === 'paid') {
            $receipt = PaymentReceipt::ensureForCharge($id);
            return ['ok'=>true,'message'=>$receipt ? 'Pagamento confirmado e comprovante criado.' : 'Pagamento confirmado, mas não foi possível criar o comprovante.'];
        }
        PaymentReceipt::removeForCharge($id);
        return ['ok'=>true,'message'=>'Cobrança marcada novamente como pendente.'];
    }

    public static function submitProof(int $chargeId, string $actorType, int $actorId, array $file): array
    {
        Database::migrate();
        $actorType = normalize_internal_actor_type($actorType);
        if (!in_array($actorType, ['student', 'beginner'], true) || $actorId <= 0) {
            return ['ok'=>false, 'message'=>'Este cadastro não pode enviar comprovante nesta cobrança.'];
        }
        $stmt = Database::pdo()->prepare('SELECT * FROM payment_charges WHERE id=? LIMIT 1');
        $stmt->execute([$chargeId]);
        $charge = $stmt->fetch();
        $chargeTypeRaw = strtolower(trim((string)($charge['recipient_type'] ?? '')));
        $chargeType = in_array($chargeTypeRaw, ['beginner', 'formacao', 'formação'], true) ? 'beginner' : 'student';
        if (!$charge || $chargeType !== $actorType || (int)$charge['recipient_id'] !== $actorId || empty($charge['is_active'])) {
            return ['ok'=>false, 'message'=>'Cobrança não encontrada ou sem acesso.'];
        }
        if (($charge['status'] ?? 'pending') !== 'pending') {
            return ['ok'=>false, 'message'=>'O pagamento desta cobrança já foi confirmado ou encerrado.'];
        }
        $saved = PortalMedia::saveGroupAttachment($file, 'payment_proofs', 10485760);
        if (empty($saved['ok'])) return $saved;

        $oldPath = (string)($charge['proof_path'] ?? '');
        $update = Database::pdo()->prepare('UPDATE payment_charges SET proof_path=?,proof_name=?,proof_mime=?,proof_size=?,proof_submitted_at=? WHERE id=?');
        $update->execute([
            $saved['path'],
            $saved['original_name'] ?? 'comprovante',
            $saved['mime_type'] ?? 'application/octet-stream',
            (int)($saved['file_size'] ?? 0),
            date('Y-m-d H:i:s'),
            $chargeId,
        ]);
        if ($oldPath !== '' && $oldPath !== ($saved['path'] ?? '')) PortalMedia::delete($oldPath);
        return ['ok'=>true, 'message'=>$oldPath !== '' ? 'Comprovante substituído e enviado ao administrador.' : 'Comprovante enviado ao administrador.'];
    }

    public static function proofForActor(int $chargeId, string $actorType, int $actorId): ?array
    {
        Database::migrate();
        $stmt = Database::pdo()->prepare('SELECT * FROM payment_charges WHERE id=? LIMIT 1');
        $stmt->execute([$chargeId]);
        $charge = $stmt->fetch();
        if (!$charge || empty($charge['proof_path'])) return null;
        $actorType = normalize_internal_actor_type($actorType);
        if ($actorType === 'admin') return $charge;
        $chargeTypeRaw = strtolower(trim((string)($charge['recipient_type'] ?? '')));
        $chargeType = in_array($chargeTypeRaw, ['beginner', 'formacao', 'formação'], true) ? 'beginner' : 'student';
        if ($chargeType !== $actorType || (int)$charge['recipient_id'] !== $actorId) return null;
        return $charge;
    }

    public static function deleteProof(int $chargeId): array
    {
        Database::migrate();
        $stmt = Database::pdo()->prepare('SELECT proof_path FROM payment_charges WHERE id=? LIMIT 1');
        $stmt->execute([$chargeId]);
        $charge = $stmt->fetch();
        if (!$charge) return ['ok'=>false, 'message'=>'Cobrança não encontrada.'];
        $path = trim((string)($charge['proof_path'] ?? ''));
        if ($path === '') return ['ok'=>false, 'message'=>'Esta cobrança não possui comprovante enviado pelo aluno.'];
        $update = Database::pdo()->prepare('UPDATE payment_charges SET proof_path=NULL,proof_name=NULL,proof_mime=NULL,proof_size=NULL,proof_submitted_at=NULL WHERE id=?');
        $update->execute([$chargeId]);
        PortalMedia::delete($path);
        return ['ok'=>true, 'message'=>'Comprovante enviado pelo aluno foi apagado. A cobrança foi preservada.'];
    }

    public static function deleteCharge(int $id): bool
    {
        Database::migrate();
        $proof = Database::pdo()->prepare('SELECT proof_path FROM payment_charges WHERE id=? LIMIT 1');
        $proof->execute([$id]);
        $proofPath = (string)($proof->fetchColumn() ?: '');
        $stmt = Database::pdo()->prepare('DELETE FROM payment_charges WHERE id=?');
        $stmt->execute([$id]);
        if ($stmt->rowCount() > 0 && $proofPath !== '') PortalMedia::delete($proofPath);
        return $stmt->rowCount() > 0;
    }
}
