/**
 * ============================================================
 * SERVIÇO DE BANCO DE DADOS — PostgreSQL (Self-Hosted)
 * Substitui todas as chamadas supabase.from(...) do sistema
 * ============================================================
 */
import pg from 'pg';

// Registrar parser global para tipo NUMERIC (OID 1700) para retornar como Number
pg.types.setTypeParser(1700, (val) => val === null ? null : parseFloat(val));

const DATABASE_URL = process.env.DATABASE_URL || 'postgresql://edumanager:EduManager2026!Seguro@postgres:5432/edumanager';

const pool = new pg.Pool({
  connectionString: DATABASE_URL,
  max: 20,
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 5000,
});

pool.on('error', (err) => {
  console.error('[PostgreSQL] Erro inesperado no pool:', err);
});

// ============================================================
// HELPER: Buscar school_data JSON blob (compatibilidade legada)
// ============================================================
export async function getSchoolData() {
  const { rows } = await pool.query(
    'SELECT data FROM school_data WHERE id = 1'
  );
  return rows[0]?.data || {};
}

/**
 * Percorre as aulas concluídas e gera registros de falta para alunos que não compareceram.
 * Isso transforma faltas "virtuais" em registros físicos no banco de dados.
 */
export async function processAutoAbsences(data) {
  if (!data.lessons || !data.students || !data.attendance) return data;

  const now = new Date();
  let updated = false;

  // 1. Auto-correção/Autolimpeza: remove faltas auto-geradas duplicadas se o aluno tiver uma presença registrada no mesmo dia/aula
  const initialLength = data.attendance.length;
  data.attendance = data.attendance.filter(a => {
    if (a.type === 'absence' && (a.autoGenerated || (a.id && a.id.startsWith('auto-abs-')))) {
      const hasPresence = data.attendance.some(p => 
        p.studentId === a.studentId && 
        (p.type === 'presence' || !p.type) && 
        (p.lessonId === a.lessonId || (p.date && a.date && p.date.substring(0, 10) === a.date.substring(0, 10)))
      );
      return !hasPresence;
    }
    return true;
  });
  if (data.attendance.length !== initialLength) {
    updated = true;
  }

  // Cleanup SQL orphaned absences as well, so SQL and JSON are consistently cleaned
  try {
    const client = await pool.connect();
    try {
      await client.query(`
        DELETE FROM frequencias a
        WHERE a.tipo = 'absence' AND a.id LIKE 'auto-abs-%'
        AND EXISTS (
            SELECT 1 FROM frequencias p
            WHERE p.tipo = 'presence'
            AND p.aluno_id = a.aluno_id
            AND (p.aula_id = a.aula_id OR DATE(p.data AT TIME ZONE 'UTC') = DATE(a.data AT TIME ZONE 'UTC'))
        )
      `);
    } finally {
      client.release();
    }
  } catch (err) {
    console.warn('[Database:AutoAbsences] Erro ao limpar faltas órfãs no SQL:', err.message);
  }

  // Cache de alunos por turma para performance
  const studentsByClass = {};

  data.lessons.forEach(lesson => {
    // RESOLUÇÃO DE FUSO HORÁRIO: Força fuso horário América/São_Paulo (-03:00) ao analisar a hora de término da aula no servidor (geralmente UTC)
    const lessonEndStr = `${lesson.date}T${lesson.endTime || '23:59'}:00-03:00`;
    const lessonEnd = new Date(lessonEndStr);

    if (now > lessonEnd && lesson.status !== 'cancelled') {
      if (!studentsByClass[lesson.classId]) {
        studentsByClass[lesson.classId] = data.students.filter(s => s.classId === lesson.classId && s.status === 'active');
      }

      studentsByClass[lesson.classId].forEach(student => {
        const hasRecord = data.attendance.some(a => 
          a.studentId === student.id && 
          (a.lessonId === lesson.id || (a.date && a.date.startsWith(lesson.date)))
        );

        if (!hasRecord) {
          data.attendance.push({
            id: `auto-abs-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`,
            studentId: student.id,
            classId: lesson.classId,
            lessonId: lesson.id,
            date: `${lesson.date}T${lesson.startTime || '00:00'}:00`,
            type: 'absence',
            verified: true,
            autoGenerated: true
          });
          updated = true;
        }
      });
    }
  });

  if (updated) {
    data.lastUpdated = new Date().toISOString();
  }
  return data;
}

export async function saveSchoolData(data) {
  // Aplicar fechamento de pauta automático antes de salvar
  const dataWithAbsences = await processAutoAbsences(data);
  
  await pool.query(
    `INSERT INTO school_data (id, data, updated_at)
     VALUES (1, $1, NOW())
     ON CONFLICT (id) DO UPDATE SET data = $1, updated_at = NOW()`,
    [JSON.stringify(dataWithAbsences)]
  );
  
  // Sincronizar tabelas relacionais em background para não travar o salvamento
  syncJsonToRelationalTables(dataWithAbsences).catch(err => 
    console.error('[Database:Sync] Erro na sincronização automática:', err)
  );
}

// ============================================================
// HELPERS: alunos_cobrancas
export async function insertCobrancas(cobrancas) {
  const client = await pool.connect();
  try {
    await client.query('BEGIN');
    for (const c of cobrancas) {
      await client.query(
        `INSERT INTO alunos_cobrancas 
         (aluno_id, asaas_customer_id, asaas_payment_id, asaas_installment_id, installment, valor, vencimento, link_boleto, amount_original)
         VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
        [c.aluno_id, c.asaas_customer_id, c.asaas_payment_id, c.asaas_installment_id || c.installment, c.installment, c.valor, c.vencimento, c.link_boleto, c.valor]
      );
    }
    await client.query('COMMIT');
  } catch (e) {
    await client.query('ROLLBACK');
    throw e;
  } finally {
    client.release();
  }
}

export async function updateCobranca(asaasPaymentId, updateData) {
  const setClauses = [];
  const values = [];
  let i = 1;

  for (const [key, value] of Object.entries(updateData)) {
    if (value !== undefined) {
      setClauses.push(`${key} = $${i}`);
      values.push(value);
      i++;
    }
  }

  if (setClauses.length === 0) return;

  values.push(asaasPaymentId);
  await pool.query(
    `UPDATE alunos_cobrancas SET ${setClauses.join(', ')} WHERE asaas_payment_id = $${i}`,
    values
  );
}

export async function deleteCobranca(asaasPaymentId) {
  await pool.query(
    'DELETE FROM alunos_cobrancas WHERE asaas_payment_id = $1',
    [asaasPaymentId]
  );
}

export async function getCobrancaByPaymentId(asaasPaymentId) {
  const { rows } = await pool.query(
    'SELECT * FROM alunos_cobrancas WHERE asaas_payment_id = $1',
    [asaasPaymentId]
  );
  return rows[0] || null;
}

export async function getCobrancasByOrQuery(id) {
  // Replicates: supabase.from('alunos_cobrancas').select('*').or(...)
  const { rows } = await pool.query(
    `SELECT * FROM alunos_cobrancas 
     WHERE installment = $1 
        OR asaas_installment_id = $1 
        OR asaas_payment_id = $1 
        OR id::text = $1
     ORDER BY vencimento ASC`,
    [id]
  );
  return rows;
}

export async function getCobrancasByAlunoId(alunoId) {
  const { rows } = await pool.query(
    'SELECT * FROM alunos_cobrancas WHERE aluno_id = $1 ORDER BY vencimento ASC',
    [alunoId]
  );
  return rows;
}

export async function getCobrancasPendentes() {
  const { rows } = await pool.query(
    "SELECT * FROM alunos_cobrancas WHERE status = 'PENDENTE'"
  );
  return rows;
}

export async function getCobrancasAtrasadas() {
  const { rows } = await pool.query(
    "SELECT * FROM alunos_cobrancas WHERE status = 'ATRASADO'"
  );
  return rows;
}

export async function getCobrancasByInstallmentId(installmentId) {
  const { rows } = await pool.query(
    'SELECT * FROM alunos_cobrancas WHERE asaas_installment_id = $1 ORDER BY vencimento ASC',
    [installmentId]
  );
  return rows;
}

export async function updateCobrancaLinkCarne(installmentId, linkCarne) {
  await pool.query(
    'UPDATE alunos_cobrancas SET link_carne = $1 WHERE asaas_installment_id = $2',
    [linkCarne, installmentId]
  );
}

export async function updateCobrancaByField(field, id, updateData) {
  const setClauses = [];
  const values = [];
  let i = 1;

  for (const [key, value] of Object.entries(updateData)) {
    if (value !== undefined) {
      setClauses.push(`${key} = $${i}`);
      values.push(value);
      i++;
    }
  }

  if (setClauses.length === 0) return;

  values.push(id);
  await pool.query(
    `UPDATE alunos_cobrancas SET ${setClauses.join(', ')} WHERE ${field} = $${i}`,
    values
  );
}

// ============================================================
// HELPERS: provas_submissoes
// ============================================================
export async function getSubmissoesByAluno(alunoId) {
  const { rows } = await pool.query(
    'SELECT * FROM provas_submissoes WHERE aluno_id = $1',
    [alunoId]
  );
  return rows;
}

export async function getSubmissaoByAlunoAndExam(alunoId, examId) {
  const { rows } = await pool.query(
    'SELECT id FROM provas_submissoes WHERE aluno_id = $1 AND prova_id = $2 LIMIT 1',
    [alunoId, examId]
  );
  return rows;
}

export async function insertSubmissao(submission) {
  await pool.query(
    `INSERT INTO provas_submissoes (aluno_id, prova_id, total_questoes, acertos, erros, percentual, nota_final, respostas, created_at)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
    [
      submission.aluno_id, submission.exam_id,
      submission.total_questions, submission.correct_count, submission.wrong_count,
      submission.percentage, submission.final_score,
      JSON.stringify(submission.answers_json), submission.created_at
    ]
  );
}

// ============================================================
// HELPERS: notas_boletim
// ============================================================
export async function initNotasTable() {
  // Remover constraints restritivas da tabela de submissões se existirem (transição JSON -> Postgres)
  try {
    await pool.query(`
      ALTER TABLE provas_submissoes DROP CONSTRAINT IF EXISTS provas_submissoes_aluno_id_fkey;
      ALTER TABLE provas_submissoes DROP CONSTRAINT IF EXISTS provas_submissoes_prova_id_fkey;
    `);
  } catch (err) {
    console.log('[PostgreSQL] ℹ️ Submissoes fkey já removidas ou tabela não existe.');
  }

  // Garantir unicidade do asaas_payment_id para permitir ON CONFLICT
  try {
    await pool.query(`
      DO $$ 
      BEGIN 
        IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'unique_asaas_payment_id') THEN
          ALTER TABLE alunos_cobrancas ADD CONSTRAINT unique_asaas_payment_id UNIQUE (asaas_payment_id);
        END IF;
      END $$;
    `);
  } catch (err) {
    console.warn('[PostgreSQL] Erro ao garantir UNIQUE em alunos_cobrancas:', err.message);
  }

  await pool.query(`
    CREATE TABLE IF NOT EXISTS notas_boletim (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      aluno_id VARCHAR(255) NOT NULL,
      disciplina_id VARCHAR(255) NOT NULL,
      periodo_id VARCHAR(255) NOT NULL,
      prova_id VARCHAR(255),
      valor NUMERIC(5, 2) NOT NULL,
      updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
      UNIQUE(aluno_id, disciplina_id, periodo_id, prova_id)
    );
  `);
}

export async function getNotasByAluno(alunoId) {
  const { rows } = await pool.query(
    'SELECT * FROM notas_boletim WHERE aluno_id = $1',
    [alunoId]
  );
  return rows;
}

export async function upsertNota(nota) {
  // Trata prova_id null se for direta para o unique index funcionar de forma previsível (PostgreSQL 15+ tem NULLS NOT DISTINCT, mas para garantir via app logic vamos usar uma abordagem de ON CONFLICT)
  // No caso do PostgreSQL padrão, múltiplos NULLs não dão conflito no UNIQUE.
  // Para contornar e permitir upsert real, faremos DELETE e INSERT ou garantiremos que o código gerencie o NULL logicamente.
  
  if (nota.prova_id) {
    await pool.query(
      `INSERT INTO notas_boletim (aluno_id, disciplina_id, periodo_id, prova_id, valor, updated_at)
       VALUES ($1, $2, $3, $4, $5, NOW())
       ON CONFLICT (aluno_id, disciplina_id, periodo_id, prova_id) 
       DO UPDATE SET valor = EXCLUDED.valor, updated_at = NOW()`,
      [nota.aluno_id, nota.disciplina_id, nota.periodo_id, nota.prova_id, nota.valor]
    );
  } else {
    // Para notas diretas, se existir apagamos e inserimos (pois o unique index normal não restringe múltiplos nulls)
    await pool.query(
      `DELETE FROM notas_boletim WHERE aluno_id = $1 AND disciplina_id = $2 AND periodo_id = $3 AND prova_id IS NULL`,
      [nota.aluno_id, nota.disciplina_id, nota.periodo_id]
    );
    await pool.query(
      `INSERT INTO notas_boletim (aluno_id, disciplina_id, periodo_id, prova_id, valor, updated_at)
       VALUES ($1, $2, $3, NULL, $4, NOW())`,
      [nota.aluno_id, nota.disciplina_id, nota.periodo_id, nota.valor]
    );
  }
}

export async function deleteNotasManuaisAusentes(alunoId, notasManuaisRetidas) {
    // Para limpar notas que o professor apagou (vazio) no manager
    // notasManuaisRetidas é um array de objetos { disciplina_id, periodo_id, prova_id }
    // Implementaremos a limpeza iterativamente na rota
}

// ============================================================
// HELPERS: cursos e turmas
// ============================================================
export async function getCursos() {
  const { rows } = await pool.query('SELECT * FROM cursos ORDER BY nome ASC');
  return rows;
}

export async function insertCurso(c) {
  await pool.query(
    `INSERT INTO cursos (id, nome, duracao, duracao_meses, taxa_matricula, mensalidade, descricao, multa_percentual, juros_percentual)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
    [c.id, c.nome, c.duracao || '', c.duracao_meses || 12, c.taxa_matricula || 0, c.mensalidade || 0, c.descricao || '', c.multa_percentual || 0, c.juros_percentual || 0]
  );
}

export async function updateCurso(id, updateData) {
  const setClauses = [];
  const values = [];
  let i = 1;

  for (const [key, value] of Object.entries(updateData)) {
    if (value !== undefined) {
      setClauses.push(`${key} = $${i}`);
      values.push(value);
      i++;
    }
  }

  if (setClauses.length === 0) return;

  values.push(id);
  await pool.query(
    `UPDATE cursos SET ${setClauses.join(', ')} WHERE id = $${i}`,
    values
  );
}

export async function deleteCurso(id) {
  await pool.query('DELETE FROM cursos WHERE id = $1', [id]);
}

export async function getTurmas() {
  const { rows } = await pool.query('SELECT * FROM turmas ORDER BY nome ASC');
  return rows;
}

export async function insertTurma(t) {
  await pool.query(
    `INSERT INTO turmas (id, nome, curso_id, professor, horario, dia_semana, max_alunos, data_inicio, data_fim, horario_inicio_padrao, horario_fim_padrao)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
    [t.id, t.nome, t.curso_id || null, t.professor || '', t.horario || '', t.dia_semana || null, t.max_alunos || 30, t.data_inicio || null, t.data_fim || null, t.horario_inicio_padrao || null, t.horario_fim_padrao || null]
  );
}

export async function updateTurma(id, updateData) {
  const setClauses = [];
  const values = [];
  let i = 1;

  for (const [key, value] of Object.entries(updateData)) {
    if (value !== undefined) {
      setClauses.push(`${key} = $${i}`);
      values.push(value);
      i++;
    }
  }

  if (setClauses.length === 0) return;

  values.push(id);
  await pool.query(
    `UPDATE turmas SET ${setClauses.join(', ')} WHERE id = $${i}`,
    values
  );
}

export async function deleteTurma(id) {
  await pool.query('DELETE FROM turmas WHERE id = $1', [id]);
}

export async function getDisciplinas() {
  const { rows } = await pool.query('SELECT * FROM disciplinas ORDER BY created_at ASC');
  return rows;
}

export async function insertDisciplina(d) {
  await pool.query(
    `INSERT INTO disciplinas (id, nome) VALUES ($1, $2)`,
    [d.id, d.nome]
  );
}

export async function updateDisciplina(id, updateData) {
  if (updateData.nome !== undefined) {
    await pool.query(
      `UPDATE disciplinas SET nome = $1 WHERE id = $2`,
      [updateData.nome, id]
    );
  }
}

export async function deleteDisciplina(id) {
  await pool.query('DELETE FROM disciplinas WHERE id = $1', [id]);
}

// ============================================================
// HELPERS: funcionarios e categorias_funcionarios
// ============================================================
export async function getFuncionarios() {
  const { rows } = await pool.query('SELECT * FROM funcionarios ORDER BY nome ASC');
  return rows.map(r => ({
    id: r.id,
    name: r.nome,
    cpf: r.cpf,
    email: r.email,
    phone: r.telefone,
    categoryId: r.categoria_id,
    hireDate: r.data_admissao,
    createdAt: r.created_at
  }));
}

export async function getCategoriasFuncionarios() {
  const { rows } = await pool.query('SELECT * FROM categorias_funcionarios ORDER BY nome ASC');
  return rows.map(r => ({
    id: r.id,
    name: r.nome,
    createdAt: r.created_at
  }));
}

export async function insertFuncionario(f) {
  await pool.query(
    `INSERT INTO funcionarios (id, nome, cpf, email, telefone, categoria_id, data_admissao)
     VALUES ($1, $2, $3, $4, $5, $6, $7)`,
    [f.id, f.nome, f.cpf, f.email, f.telefone, f.categoria_id, f.data_admissao || null]
  );
}

export async function updateFuncionario(id, updateData) {
  const setClauses = [];
  const values = [];
  let i = 1;

  for (const [key, value] of Object.entries(updateData)) {
    if (value !== undefined) {
      setClauses.push(`${key} = $${i}`);
      values.push(value);
      i++;
    }
  }

  if (setClauses.length === 0) return;

  values.push(id);
  await pool.query(
    `UPDATE funcionarios SET ${setClauses.join(', ')} WHERE id = $${i}`,
    values
  );
}

export async function deleteFuncionario(id) {
  await pool.query('DELETE FROM funcionarios WHERE id = $1', [id]);
}

export async function insertCategoriaFuncionario(c) {
  await pool.query(
    `INSERT INTO categorias_funcionarios (id, nome) VALUES ($1, $2)`,
    [c.id, c.nome]
  );
}

export async function updateCategoriaFuncionario(id, nome) {
  await pool.query(
    `UPDATE categorias_funcionarios SET nome = $1 WHERE id = $2`,
    [nome, id]
  );
}

export async function deleteCategoriaFuncionario(id) {
  await pool.query('DELETE FROM categorias_funcionarios WHERE id = $1', [id]);
}

// ============================================================
// ALUNOS (FASE 4)
// ============================================================
function formatDateOnly(val) {
  if (!val) return null;
  if (val instanceof Date) {
    const year = val.getFullYear();
    const month = String(val.getMonth() + 1).padStart(2, '0');
    const day = String(val.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
  }
  if (typeof val === 'string') {
    return val.substring(0, 10);
  }
  return String(val).substring(0, 10);
}

export async function getAlunos() {
  const result = await pool.query("SELECT * FROM alunos ORDER BY nome ASC");
  return result.rows.map(r => ({
    ...r,
    id: r.id,
    name: r.nome,
    email: r.email,
    phone: r.telefone,
    birthDate: formatDateOnly(r.data_nascimento),
    cpf: r.cpf,
    rg: r.rg,
    rgIssueDate: formatDateOnly(r.rg_data_emissao),
    guardianName: r.nome_responsavel,
    guardianPhone: r.telefone_responsavel,
    guardianCpf: r.cpf_responsavel,
    guardianBirthDate: formatDateOnly(r.data_nascimento_responsavel),
    classId: r.turma_id,
    status: r.status,
    registrationDate: formatDateOnly(r.data_matricula),
    photo: r.foto_url,
    addressZip: r.cep,
    addressStreet: r.rua,
    addressNumber: r.numero,
    addressNeighborhood: r.bairro,
    addressCity: r.cidade,
    addressState: r.estado,
    discount: r.desconto,
    hasGuardian: r.tem_responsavel,
    contractTemplateId: r.modelo_contrato_id,
    enrollmentNumber: r.numero_matricula,
    portalPassword: r.senha_portal,
    cancellationReason: r.motivo_cancelamento,
    faceDescriptor: r.face_descriptor,
    sexo: r.sexo
  }));
}

export async function insertAluno(a) {
  const birthDate = (a.data_nascimento || a.birthDate) ? formatDateOnly(a.data_nascimento || a.birthDate) : null;
  const rgIssueDate = (a.rg_data_emissao || a.rgIssueDate) ? formatDateOnly(a.rg_data_emissao || a.rgIssueDate) : null;
  const guardianBirthDate = (a.data_nascimento_responsavel || a.guardianBirthDate) ? formatDateOnly(a.data_nascimento_responsavel || a.guardianBirthDate) : null;
  const registrationDate = (a.data_matricula || a.registrationDate) ? formatDateOnly(a.data_matricula || a.registrationDate) : null;

  const result = await pool.query(
    `INSERT INTO alunos (
      id, nome, email, telefone, data_nascimento, cpf, rg, rg_data_emissao,
      nome_responsavel, telefone_responsavel, cpf_responsavel, data_nascimento_responsavel,
      turma_id, status, data_matricula, foto_url, cep, rua, numero, bairro, cidade, estado,
      desconto, tem_responsavel, modelo_contrato_id, numero_matricula, senha_portal,
      motivo_cancelamento, face_descriptor, sexo
    ) VALUES (
      $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30
    ) RETURNING *`,
    [
      a.id, a.nome || a.name, a.email || '', a.telefone || a.phone || '', birthDate,
      a.cpf || '', a.rg || '', rgIssueDate,
      a.nome_responsavel || a.guardianName || '', a.telefone_responsavel || a.guardianPhone || '',
      a.cpf_responsavel || a.guardianCpf || '', guardianBirthDate,
      a.turma_id || a.classId || null, a.status || 'active', registrationDate,
      a.foto_url || a.photo || '', a.cep || a.addressZip || '', a.rua || a.addressStreet || '',
      a.numero || a.addressNumber || '', a.bairro || a.addressNeighborhood || '', a.cidade || a.addressCity || '',
      a.estado || a.addressState || '', a.desconto || a.discount || 0, a.tem_responsavel !== undefined ? a.tem_responsavel : (a.hasGuardian || false),
      a.modelo_contrato_id || a.contractTemplateId || null, a.numero_matricula || a.enrollmentNumber || null,
      a.senha_portal || a.portalPassword || null, a.motivo_cancelamento || a.cancellationReason || null,
      a.faceDescriptor ? JSON.stringify(a.faceDescriptor) : null,
      a.sexo || null
    ]
  );
  return result.rows[0];
}

export async function updateAluno(id, a) {
  const birthDate = (a.data_nascimento || a.birthDate) ? formatDateOnly(a.data_nascimento || a.birthDate) : null;
  const rgIssueDate = (a.rg_data_emissao || a.rgIssueDate) ? formatDateOnly(a.rg_data_emissao || a.rgIssueDate) : null;
  const guardianBirthDate = (a.data_nascimento_responsavel || a.guardianBirthDate) ? formatDateOnly(a.data_nascimento_responsavel || a.guardianBirthDate) : null;
  const registrationDate = (a.data_matricula || a.registrationDate) ? formatDateOnly(a.data_matricula || a.registrationDate) : null;

  const result = await pool.query(
    `UPDATE alunos SET
      nome=$1, email=$2, telefone=$3, data_nascimento=$4, cpf=$5, rg=$6, rg_data_emissao=$7,
      nome_responsavel=$8, telefone_responsavel=$9, cpf_responsavel=$10, data_nascimento_responsavel=$11,
      turma_id=$12, status=$13, data_matricula=$14, foto_url=$15, cep=$16, rua=$17, numero=$18, bairro=$19, cidade=$20, estado=$21,
      desconto=$22, tem_responsavel=$23, modelo_contrato_id=$24, numero_matricula=$25, senha_portal=$26,
      motivo_cancelamento=$27, face_descriptor=COALESCE($28, face_descriptor), sexo=$29
     WHERE id = $30 RETURNING *`,
    [
      a.nome || a.name, a.email || '', a.telefone || a.phone || '', birthDate,
      a.cpf || '', a.rg || '', rgIssueDate,
      a.nome_responsavel || a.guardianName || '', a.telefone_responsavel || a.guardianPhone || '',
      a.cpf_responsavel || a.guardianCpf || '', guardianBirthDate,
      a.turma_id || a.classId || null, a.status || 'active', registrationDate,
      a.foto_url || a.photo || '', a.cep || a.addressZip || '', a.rua || a.addressStreet || '',
      a.numero || a.addressNumber || '', a.bairro || a.addressNeighborhood || '', a.cidade || a.addressCity || '',
      a.estado || a.addressState || '', a.desconto || a.discount || 0, a.tem_responsavel !== undefined ? a.tem_responsavel : (a.hasGuardian || false),
      a.modelo_contrato_id || a.contractTemplateId || null, a.numero_matricula || a.enrollmentNumber || null,
      a.senha_portal || a.portalPassword || null, a.motivo_cancelamento || a.cancellationReason || null,
      a.faceDescriptor ? JSON.stringify(a.faceDescriptor) : null,
      a.sexo || null,
      id
    ]
  );
  return result.rows[0];
}

export async function deleteAluno(id) {
  await pool.query('DELETE FROM alunos WHERE id = $1', [id]);
}

// ============================================================
// CONTRATOS E MODELOS
// ============================================================
export async function getModelosContrato() {
  const { rows } = await pool.query('SELECT * FROM modelos_contrato ORDER BY nome ASC');
  return rows.map(r => ({ id: r.id, name: r.nome, content: r.conteudo }));
}

export async function insertModeloContrato(m) {
  await pool.query('INSERT INTO modelos_contrato (id, nome, conteudo) VALUES ($1, $2, $3)', [m.id, m.name, m.content]);
}

export async function updateModeloContrato(id, m) {
  await pool.query('UPDATE modelos_contrato SET nome=$1, conteudo=$2 WHERE id=$3', [m.name, m.content, id]);
}

export async function deleteModeloContrato(id) {
  await pool.query('DELETE FROM modelos_contrato WHERE id=$1', [id]);
}

export async function getContratos() {
  const { rows } = await pool.query('SELECT *, TO_CHAR(created_at, \'YYYY-MM-DD"T"HH24:MI:SS"Z"\') as created_at_fmt FROM contratos ORDER BY created_at DESC');
  return rows.map(r => ({ id: r.id, studentId: r.aluno_id, title: r.titulo, content: r.conteudo, createdAt: r.created_at_fmt }));
}

export async function insertContrato(c) {
  await pool.query('INSERT INTO contratos (id, aluno_id, titulo, conteudo) VALUES ($1, $2, $3, $4)', [c.id, c.studentId, c.title, c.content]);
}

export async function updateContrato(id, c) {
  await pool.query('UPDATE contratos SET titulo=$1, conteudo=$2 WHERE id=$3', [c.title, c.content, id]);
}

export async function deleteContrato(id) {
  await pool.query('DELETE FROM contratos WHERE id=$1', [id]);
}

// ============================================================
// AULAS E CRONOGRAMA
// ============================================================
export async function getAulasByTurma(turma_id) {
  const result = await pool.query(
    `SELECT *, TO_CHAR(data, 'YYYY-MM-DD') as data_formatada FROM aulas WHERE turma_id = $1 ORDER BY data ASC, horario_inicio ASC`,
    [turma_id]
  );
  return result.rows.map(row => ({
    id: row.id,
    classId: row.turma_id,
    date: row.data_formatada,
    startTime: row.horario_inicio,
    endTime: row.horario_fim,
    status: row.status,
    type: row.tipo,
    cancellationReason: row.motivo_cancelamento,
    originalLessonId: row.aula_original_id
  }));
}

export async function getAllAulas() {
  const result = await pool.query(
    `SELECT *, TO_CHAR(data, 'YYYY-MM-DD') as data_formatada FROM aulas ORDER BY data ASC, horario_inicio ASC`
  );
  return result.rows.map(row => ({
    id: row.id,
    classId: row.turma_id,
    date: row.data_formatada,
    startTime: row.horario_inicio,
    endTime: row.horario_fim,
    status: row.status,
    type: row.tipo,
    cancellationReason: row.motivo_cancelamento,
    originalLessonId: row.aula_original_id
  }));
}

export async function insertAulas(aulas) {
  const client = await pool.connect();
  try {
    await client.query('BEGIN');
    for (const a of aulas) {
      await client.query(
        `INSERT INTO aulas (
          id, turma_id, data, horario_inicio, horario_fim, status, tipo, motivo_cancelamento, aula_original_id
        ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
        ON CONFLICT (id) DO UPDATE SET
          turma_id=$2, data=$3, horario_inicio=$4, horario_fim=$5, status=$6, tipo=$7, motivo_cancelamento=$8, aula_original_id=$9`,
        [
          a.id, a.classId, a.date, a.startTime, a.endTime, a.status || 'scheduled', a.type || 'regular',
          a.cancellationReason || null, a.originalLessonId || null
        ]
      );
    }
    await client.query('COMMIT');
  } catch (e) {
    await client.query('ROLLBACK');
    throw e;
  } finally {
    client.release();
  }
}

export async function deleteAulas(ids) {
  if (!ids || ids.length === 0) return;
  await pool.query('DELETE FROM aulas WHERE id = ANY($1)', [ids]);
}

// ============================================================
// FREQUÊNCIAS (CHAMADA)
// ============================================================
export async function getFrequencias() {
  const { rows } = await pool.query(`
    SELECT *, TO_CHAR(data, 'YYYY-MM-DD"T"HH24:MI:SS') as formatted_data 
    FROM frequencias ORDER BY created_at DESC
  `);
  return rows.map(r => ({
    id: r.id,
    studentId: r.aluno_id,
    classId: r.turma_id,
    lessonId: r.aula_id,
    date: r.formatted_data || r.data,
    photo: r.foto_url || r.foto,
    verified: r.verificado,
    type: r.tipo,
    justification: r.justificativa,
    justificationAccepted: r.justificativa_aceita,
    createdAt: r.created_at
  }));
}

export async function insertFrequencia(f) {
  await pool.query(
    `INSERT INTO frequencias (id, aluno_id, turma_id, aula_id, data, foto, verificado, tipo, justificativa, justificativa_aceita)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,
    [
      f.id, f.studentId, f.classId, f.lessonId, f.date, f.photo, 
      f.verified || false, f.type || 'presence', f.justification, f.justificationAccepted || false
    ]
  );
}

export async function updateFrequencia(id, f) {
  // Update apenas dos campos que podem mudar
  await pool.query(
    `UPDATE frequencias 
     SET tipo = $1, justificativa = $2, justificativa_aceita = $3, verificado = $4
     WHERE id = $5`,
    [f.type, f.justification, f.justificationAccepted, f.verified, id]
  );
}

export async function deleteFrequencia(id) {
  await pool.query('DELETE FROM frequencias WHERE id = $1', [id]);
}

// ============================================================
// PROVAS & QUESTÕES (FASE 5)
// ============================================================
export async function getProvas() {
  const { rows: provasRows } = await pool.query('SELECT * FROM provas ORDER BY created_at DESC');
  
  // Mapear campos para camelCase e buscar questoes para compatibilidade com o frontend antigo
  const provasFormatadas = [];
  for (const p of provasRows) {
    const { rows: questoesRows } = await pool.query('SELECT * FROM questoes_provas WHERE prova_id = $1 ORDER BY ordem ASC', [p.id]);
    
    provasFormatadas.push({
      id: p.id,
      classId: p.turma_id,
      subjectId: p.disciplina_id,
      periodId: p.periodo_id,
      title: p.titulo,
      durationMinutes: p.duracao_minutos,
      status: p.status,
      allowRetake: p.permitir_refacao,
      isDeleted: p.is_deleted,
      evaluationType: p.evaluation_type || 'exam',
      maxScore: p.max_score !== null && p.max_score !== undefined ? Number(p.max_score) : 10.0,
      questions: questoesRows.map(q => ({
        id: q.id,
        examId: q.prova_id,
        text: q.texto,
        options: q.opcoes || [],
        correctOptionIndex: q.indice_correto ?? 0,
        order: q.ordem,
        imageUrl: q.imagem_url
      }))
    });
  }
  return provasFormatadas;
}

export async function getQuestoesDaProva(provaId) {
  const result = await pool.query('SELECT * FROM questoes_provas WHERE prova_id = $1 ORDER BY ordem ASC', [provaId]);
  return result.rows;
}

export async function insertProva(p) {
  await pool.query(
    `INSERT INTO provas (id, turma_id, disciplina_id, periodo_id, titulo, duracao_minutos, status, permitir_refacao, is_deleted, evaluation_type, max_score)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
    [
      p.id, p.turma_id || p.classId, p.disciplina_id || p.subjectId, p.periodo_id || p.periodId, 
      p.titulo || p.title, p.duracao_minutos || p.durationMinutes || 60, p.status || 'draft', 
      p.permitir_refacao || p.allowRetake || false,
      p.is_deleted || p.isDeleted || false,
      p.evaluation_type || p.evaluationType || 'exam',
      p.maxScore !== undefined && p.maxScore !== null ? Number(p.maxScore) : 10.0
    ]
  );
}

export async function updateProva(id, p) {
  await pool.query(
    `UPDATE provas SET 
     turma_id = $1, disciplina_id = $2, periodo_id = $3, titulo = $4, duracao_minutos = $5, status = $6, permitir_refacao = $7, is_deleted = $8, evaluation_type = $9, max_score = $10
     WHERE id = $11`,
    [
      p.turma_id || p.classId, p.disciplina_id || p.subjectId, p.periodo_id || p.periodId, 
      p.titulo || p.title, p.duracao_minutos || p.durationMinutes || 60, p.status || 'draft', 
      p.permitir_refacao || p.allowRetake || false,
      p.is_deleted || p.isDeleted || false,
      p.evaluation_type || p.evaluationType || 'exam',
      p.maxScore !== undefined && p.maxScore !== null ? Number(p.maxScore) : 10.0,
      id
    ]
  );
}

export async function deleteProva(id) {
  await pool.query('DELETE FROM provas WHERE id = $1', [id]);
}

export async function syncQuestoesProva(provaId, questoes) {
  const client = await pool.connect();
  try {
    await client.query('BEGIN');
    await client.query('DELETE FROM questoes_provas WHERE prova_id = $1', [provaId]);
    for (let i = 0; i < questoes.length; i++) {
      const q = questoes[i];
      await client.query(
        `INSERT INTO questoes_provas (id, prova_id, texto, imagem_url, opcoes, indice_correto, ordem)
         VALUES ($1, $2, $3, $4, $5, $6, $7)`,
        [q.id || require('crypto').randomUUID(), provaId, q.texto || q.text, q.imagem_url || q.imageUrl, JSON.stringify(q.opcoes || q.options || []), q.indice_correto ?? q.correctOptionIndex ?? q.correctIndex ?? 0, i]
      );
    }
    await client.query('COMMIT');
  } catch (e) {
    await client.query('ROLLBACK');
    throw e;
  } finally {
    client.release();
  }
}

// ============================================================
// SINCRONIZAÇÃO: JSON -> TABELAS RELACIONAIS
// Garante que IDs do JSON existam nas tabelas para evitar erro de Foreign Key
// ============================================================
export async function syncJsonToRelationalTables() {
  const client = await pool.connect();
  try {
    const data = await getSchoolData();
    if (!data) return;

    console.log('[Sincronização] 🔄 Iniciando espelhamento TOTAL (Modo Blindado)...');
    await client.query('BEGIN');

    // Garantir colunas na tabela frequencias
    await client.query(`ALTER TABLE frequencias ADD COLUMN IF NOT EXISTS justificativa TEXT`);
    await client.query(`ALTER TABLE frequencias ADD COLUMN IF NOT EXISTS justificativa_aceita BOOLEAN DEFAULT FALSE`);

    // 1. Sincronizar Cursos
    if (data.courses && Array.isArray(data.courses)) {
      const courseIds = data.courses.map(c => c.id).filter(Boolean);
      if (courseIds.length > 0) {
        await client.query('DELETE FROM cursos WHERE id != ALL($1)', [courseIds]);
      } else {
        await client.query('DELETE FROM cursos');
      }

      for (const c of data.courses) {
        if (!c.id || !c.name) continue;
        await client.query(
          `INSERT INTO cursos (id, nome, duracao, duracao_meses, taxa_matricula, mensalidade, descricao, multa_percentual, juros_percentual)
           VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
           ON CONFLICT (id) DO UPDATE SET 
            nome = EXCLUDED.nome, duracao = EXCLUDED.duracao, duracao_meses = EXCLUDED.duracao_meses,
            taxa_matricula = EXCLUDED.taxa_matricula, mensalidade = EXCLUDED.mensalidade,
            descricao = EXCLUDED.descricao, multa_percentual = EXCLUDED.multa_percentual,
            juros_percentual = EXCLUDED.juros_percentual`,
          [c.id, c.name, c.duration || '', c.durationMonths || 0, c.registrationFee || 0, c.monthlyFee || 0, c.description || '', c.finePercentage || 0, c.interestPercentage || 0]
        );
      }
    }

    // 1.5 Sincronizar Categorias de Funcionários
    if (data.employeeCategories && Array.isArray(data.employeeCategories)) {
      for (const cat of data.employeeCategories) {
        if (!cat.id || !cat.name) continue;
        await client.query(
          `INSERT INTO categorias_funcionarios (id, nome) VALUES ($1, $2)
           ON CONFLICT (id) DO UPDATE SET nome = EXCLUDED.nome`,
          [cat.id, cat.name]
        );
      }
    }

    // 1.6 Sincronizar Funcionários
    if (data.employees && Array.isArray(data.employees)) {
      for (const emp of data.employees) {
        if (!emp.id || !emp.name) continue;
        await client.query(
          `INSERT INTO funcionarios (id, nome, cpf, email, telefone, categoria_id, data_admissao)
           VALUES ($1, $2, $3, $4, $5, $6, $7)
           ON CONFLICT (id) DO UPDATE SET 
            nome = EXCLUDED.nome, cpf = EXCLUDED.cpf, email = EXCLUDED.email, 
            telefone = EXCLUDED.telefone, categoria_id = EXCLUDED.categoria_id, 
            data_admissao = EXCLUDED.data_admissao`,
          [emp.id, emp.name, emp.cpf || '', emp.email || '', emp.phone || '', emp.categoryId || null, emp.admissionDate || null]
        );
      }
    }

    // Garantir colunas de refação e soft delete em provas
    await client.query('ALTER TABLE provas ADD COLUMN IF NOT EXISTS permitir_refacao BOOLEAN DEFAULT FALSE');
    await client.query('ALTER TABLE provas ADD COLUMN IF NOT EXISTS is_deleted BOOLEAN DEFAULT FALSE');
    await client.query("ALTER TABLE provas ADD COLUMN IF NOT EXISTS evaluation_type VARCHAR(50) DEFAULT 'exam'");

    // 2. Sincronizar Disciplinas (Subjects)
    if (data.subjects && Array.isArray(data.subjects)) {
      const subIds = data.subjects.map(s => s.id).filter(Boolean);
      if (subIds.length > 0) {
        await client.query('DELETE FROM disciplinas WHERE id != ALL($1)', [subIds]);
      } else {
        await client.query('DELETE FROM disciplinas');
      }

      for (const sub of data.subjects) {
        if (!sub.id || !sub.name) continue;
        await client.query(
          `INSERT INTO disciplinas (id, nome)
           VALUES ($1, $2)
           ON CONFLICT (id) DO UPDATE SET nome = EXCLUDED.nome`,
          [sub.id, sub.name]
        );
      }
    }

    // 0. Garantir esquema atualizado
    await client.query('ALTER TABLE alunos_cobrancas ADD COLUMN IF NOT EXISTS valor_pago NUMERIC(10,2) DEFAULT 0');
    await client.query('ALTER TABLE alunos_cobrancas ADD COLUMN IF NOT EXISTS local_id VARCHAR(255)');
    await client.query('CREATE INDEX IF NOT EXISTS idx_cobrancas_local_id ON alunos_cobrancas(local_id)');
    
    // 1. Sincronizar Perfil da Escola (Configurações)
    if (data.periods && Array.isArray(data.periods)) {
      const periodIds = data.periods.map(p => p.id).filter(Boolean);
      if (periodIds.length > 0) {
        await client.query('DELETE FROM periodos WHERE id != ALL($1)', [periodIds]);
      } else {
        await client.query('DELETE FROM periodos');
      }

      for (const p of data.periods) {
        if (!p.id || !p.name) continue;
        await client.query(
          `INSERT INTO periodos (id, nome)
           VALUES ($1, $2)
           ON CONFLICT (id) DO UPDATE SET nome = EXCLUDED.nome`,
          [p.id, p.name]
        );
      }
    }

    // 4. Sincronizar Turmas
    if (data.classes && Array.isArray(data.classes)) {
      const classIds = data.classes.map(t => t.id).filter(Boolean);
      if (classIds.length > 0) {
        await client.query('DELETE FROM turmas WHERE id != ALL($1)', [classIds]);
      } else {
        await client.query('DELETE FROM turmas');
      }

      for (const t of data.classes) {
        if (!t.id || !t.name) continue;
        await client.query(
          `INSERT INTO turmas (id, nome, curso_id, professor, horario, dia_semana, max_alunos, data_inicio, data_fim, horario_inicio_padrao, horario_fim_padrao)
           VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
           ON CONFLICT (id) DO UPDATE SET 
            nome = EXCLUDED.nome, curso_id = EXCLUDED.curso_id, professor = EXCLUDED.professor,
            horario = EXCLUDED.horario, dia_semana = EXCLUDED.dia_semana, max_alunos = EXCLUDED.max_alunos,
            data_inicio = EXCLUDED.data_inicio, data_fim = EXCLUDED.data_fim,
            horario_inicio_padrao = EXCLUDED.horario_inicio_padrao, horario_fim_padrao = EXCLUDED.horario_fim_padrao`,
          [t.id, t.name, t.courseId || null, t.teacher || '', t.schedule || '', t.scheduleDay || null, t.maxStudents || 30, t.startDate || null, t.endDate || null, t.defaultStartTime || null, t.defaultEndTime || null]
        );
      }
    }

    // 5. Sincronizar Alunos
    if (data.students && Array.isArray(data.students)) {
      const studentIds = data.students.map(s => s.id).filter(Boolean);
      if (studentIds.length > 0) {
        await client.query('DELETE FROM alunos WHERE id != ALL($1)', [studentIds]);
      } else {
        await client.query('DELETE FROM alunos');
      }

      for (const s of data.students) {
        if (!s.id || !s.name) continue;
        await client.query(
          `INSERT INTO alunos (
            id, nome, email, telefone, data_nascimento, cpf, rg, rg_data_emissao,
            nome_responsavel, telefone_responsavel, cpf_responsavel, data_nascimento_responsavel,
            turma_id, status, data_matricula, foto_url, cep, rua, numero, bairro, cidade, estado,
            desconto, tem_responsavel, modelo_contrato_id, numero_matricula, senha_portal, face_descriptor, sexo
          ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29)
          ON CONFLICT (id) DO UPDATE SET 
            nome = EXCLUDED.nome, email = EXCLUDED.email, telefone = EXCLUDED.telefone, data_nascimento = EXCLUDED.data_nascimento,
            cpf = EXCLUDED.cpf, rg = EXCLUDED.rg, rg_data_emissao = EXCLUDED.rg_data_emissao,
            nome_responsavel = EXCLUDED.nome_responsavel, telefone_responsavel = EXCLUDED.telefone_responsavel,
            cpf_responsavel = EXCLUDED.cpf_responsavel, data_nascimento_responsavel = EXCLUDED.data_nascimento_responsavel,
            turma_id = EXCLUDED.turma_id, status = EXCLUDED.status, data_matricula = EXCLUDED.data_matricula,
            foto_url = EXCLUDED.foto_url, cep = EXCLUDED.cep, rua = EXCLUDED.rua, numero = EXCLUDED.numero,
            bairro = EXCLUDED.bairro, cidade = EXCLUDED.cidade, estado = EXCLUDED.estado,
            desconto = EXCLUDED.desconto, tem_responsavel = EXCLUDED.tem_responsavel,
            modelo_contrato_id = EXCLUDED.modelo_contrato_id, numero_matricula = EXCLUDED.numero_matricula,
            senha_portal = EXCLUDED.senha_portal, face_descriptor = COALESCE(EXCLUDED.face_descriptor, alunos.face_descriptor),
            sexo = EXCLUDED.sexo`,
          [
            s.id, s.name || s.nome, s.email || '', s.phone || s.telefone || '', s.birthDate || s.data_nascimento || null, s.cpf || '', s.rg || '', s.rgIssueDate || s.rg_data_emissao || null,
            s.guardianName || s.nome_responsavel || '', s.guardianPhone || s.telefone_responsavel || '', s.guardianCpf || s.cpf_responsavel || '', s.guardianBirthDate || s.data_nascimento_responsavel || null,
            s.classId || s.turma_id || null, s.status || 'active', s.registrationDate || s.data_matricula || null, s.photo || s.foto_url || '',
            s.addressZip || s.cep || '', s.addressStreet || s.rua || '', s.addressNumber || s.numero || '', s.addressNeighborhood || s.bairro || '', s.addressCity || s.cidade || '', s.addressState || s.estado || '',
            s.discount || s.desconto || 0, s.hasGuardian !== undefined ? s.hasGuardian : (s.tem_responsavel || false), s.contractTemplateId || s.modelo_contrato_id || null, s.enrollmentNumber || s.numero_matricula || null, s.portalPassword || s.senha_portal || null,
            s.faceDescriptor ? JSON.stringify(s.faceDescriptor) : null,
            s.sexo || null
          ]
        );
      }
    }

    // 6. Sincronizar Provas
    if (data.exams && Array.isArray(data.exams)) {
      const examIds = data.exams.map(e => e.id).filter(Boolean);
      if (examIds.length > 0) {
        await client.query('DELETE FROM provas WHERE id != ALL($1)', [examIds]);
      } else {
        await client.query('DELETE FROM provas');
      }

      for (const e of data.exams) {
        if (!e.id || !e.title) continue;
        await client.query(
          `INSERT INTO provas (id, turma_id, disciplina_id, periodo_id, titulo, duracao_minutos, status, permitir_refacao)
           VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
           ON CONFLICT (id) DO UPDATE SET 
            turma_id = EXCLUDED.turma_id, disciplina_id = EXCLUDED.disciplina_id, periodo_id = EXCLUDED.periodo_id,
            titulo = EXCLUDED.titulo, duracao_minutos = EXCLUDED.duracao_minutos, status = EXCLUDED.status,
            permitir_refacao = EXCLUDED.permitir_refacao`,
          [e.id, e.classId || null, e.subjectId || null, e.periodId || null, e.title, e.durationMinutes || 60, e.status || 'draft', e.allowRetake || false]
        ).catch(err => console.warn(`[Sync:Provas] Erro na prova ${e.id}:`, err.message));
      }
    }

    // 7. Sincronizar Frequências
    // [REMOVIDO] A tabela de frequencias agora é a Single Source of Truth (SQL-First).
    // O JSON legado data.attendance é ignorado para não sobrescrever os registros reais do banco.

    // 8. Sincronizar Cobranças (Financeiro) — com campos ricos para migração SQL-First
    if (data.payments && Array.isArray(data.payments)) {
      for (const p of data.payments) {
        if (!p.studentId || !p.id) continue;
        
        // Normalizar status para o padrão SQL (maiúsculas)
        const rawStatus = (p.status || 'pending').toLowerCase();
        const statusMap = { 'paid': 'PAGO', 'received': 'PAGO', 'confirmed': 'PAGO', 'overdue': 'ATRASADO', 'cancelled': 'CANCELADO' };
        const sqlStatus = statusMap[rawStatus] || 'PENDENTE';
        const isPaid = sqlStatus === 'PAGO';
        const amount = Number(p.amount || 0);
        const discount = Number(p.discount || 0);
        
        // O valor da parcela (face value) é sempre o amount do JSON (ex: 170)
        // O desconto é condicional e NÃO altera o valor base da parcela
        let valorBruto = amount;
        let valorPago = 0;

        if (isPaid) {
          // Usar valor_pago explícito do JSON se disponível, senão calcular (amount - discount)
          valorPago = Number(p.valor_pago || 0) || (amount - discount);
        }

        if (p.asaasPaymentId) {
          // Cobrança vinculada ao Asaas (usa ON CONFLICT em asaas_payment_id)
          await client.query(
            `INSERT INTO alunos_cobrancas (
              local_id, aluno_id, asaas_payment_id, asaas_installment_id, installment, 
              valor, vencimento, link_boleto, status,
              description, type, discount, installment_number, total_installments,
              contract_id, asaas_payment_url, amount_original, data_pagamento, valor_pago
            ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)
            ON CONFLICT (asaas_payment_id) DO UPDATE SET 
              local_id = COALESCE(EXCLUDED.local_id, alunos_cobrancas.local_id),
              aluno_id = EXCLUDED.aluno_id,
              asaas_installment_id = COALESCE(EXCLUDED.asaas_installment_id, alunos_cobrancas.asaas_installment_id),
              installment = COALESCE(EXCLUDED.installment, alunos_cobrancas.installment),
              valor = EXCLUDED.valor,
              vencimento = EXCLUDED.vencimento,
              link_boleto = COALESCE(EXCLUDED.link_boleto, alunos_cobrancas.link_boleto),
              status = CASE WHEN alunos_cobrancas.status = 'PAGO' THEN alunos_cobrancas.status ELSE EXCLUDED.status END,
              description = COALESCE(EXCLUDED.description, alunos_cobrancas.description),
              type = COALESCE(EXCLUDED.type, alunos_cobrancas.type),
              discount = COALESCE(EXCLUDED.discount, alunos_cobrancas.discount),
              installment_number = COALESCE(EXCLUDED.installment_number, alunos_cobrancas.installment_number),
              total_installments = COALESCE(EXCLUDED.total_installments, alunos_cobrancas.total_installments),
              contract_id = COALESCE(EXCLUDED.contract_id, alunos_cobrancas.contract_id),
              asaas_payment_url = COALESCE(EXCLUDED.asaas_payment_url, alunos_cobrancas.asaas_payment_url),
              amount_original = COALESCE(EXCLUDED.amount_original, alunos_cobrancas.amount_original),
              data_pagamento = COALESCE(EXCLUDED.data_pagamento, alunos_cobrancas.data_pagamento),
              valor_pago = EXCLUDED.valor_pago`,
            [
              p.id,
              p.studentId, 
              p.asaasPaymentId, 
              p.asaasInstallmentId || p.installmentId || null, 
              p.installment || null,
              valorBruto, 
              p.dueDate, 
              p.bankSlipUrl || p.link || null, 
              sqlStatus,
              p.description || null,
              p.type || 'monthly',
              discount,
              p.installmentNumber || null,
              p.totalInstallments || null,
              p.contractId || null,
              p.asaasPaymentUrl || null,
              valorBruto,
              p.paidDate || null,
              valorPago
            ]
          ).catch(err => console.warn(`[Sync:Finance] Erro no boleto Asaas ${p.asaasPaymentId}:`, err.message));
        } else {
          // Cobrança manual (sem asaasPaymentId)
          // Verificamos por local_id para evitar duplicação
          const existing = await client.query('SELECT id FROM alunos_cobrancas WHERE local_id = $1', [p.id]);
          if (existing.rows.length > 0) {
            await client.query(
              `UPDATE alunos_cobrancas SET
                aluno_id = $1,
                valor = $2,
                vencimento = $3,
                status = $4,
                description = $5,
                type = $6,
                discount = $7,
                installment_number = $8,
                total_installments = $9,
                contract_id = $10,
                amount_original = $11,
                data_pagamento = $12,
                valor_pago = $13
              WHERE local_id = $14`,
              [
                p.studentId,
                valorBruto,
                p.dueDate,
                sqlStatus,
                p.description || null,
                p.type || 'monthly',
                discount,
                p.installmentNumber || null,
                p.totalInstallments || null,
                p.contractId || null,
                valorBruto,
                p.paidDate || null,
                valorPago,
                p.id
              ]
            ).catch(err => console.warn(`[Sync:Finance] Erro ao atualizar boleto manual ${p.id}:`, err.message));
          } else {
            await client.query(
              `INSERT INTO alunos_cobrancas (
                local_id, aluno_id, valor, vencimento, status,
                description, type, discount, installment_number, total_installments,
                contract_id, amount_original, data_pagamento, valor_pago
              ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)`,
              [
                p.id,
                p.studentId,
                valorBruto,
                p.dueDate,
                sqlStatus,
                p.description || null,
                p.type || 'monthly',
                discount,
                p.installmentNumber || null,
                p.totalInstallments || null,
                p.contractId || null,
                valorBruto,
                p.paidDate || null,
                valorPago
              ]
            ).catch(err => console.warn(`[Sync:Finance] Erro ao inserir boleto manual ${p.id}:`, err.message));
          }
        }
      }
    }

    await client.query('COMMIT');
    console.log('[Sincronização] 🚀 Espelhamento TOTAL concluído com sucesso!');
  } catch (err) {
    await client.query('ROLLBACK');
    console.error('[Sincronização] ❌ Erro Crítico:', err.message);
  } finally {
    client.release();
  }
}

// ============================================================
// EXPORT POOL para queries diretas quando necessário
// ============================================================
export { pool };
export default pool;
