const { Client } = require('pg');
const mysql = require('mysql2/promise');
const dotenv = require('dotenv');
const fs = require('fs');
const moment = require('moment');

dotenv.config();

const envData = fs.readFileSync('conecta.env', 'utf8');
const envVariables = dotenv.parse(envData);

const {
  DB_PG_SERVER,
  DB_PG_PORT,
  DB_PG_USERNAME,
  DB_PG_PASSWORD,
  DB_PG_NAME,
  DB_MYSQL_SERVER,
  DB_MYSQL_USERNAME,
  DB_MYSQL_PASSWORD,
  DB_MYSQL_NAME,
} = envVariables;

const TABLE_NAME = 'tb_hist_esus_oci';
const TABLE_NAME_NEW = 'tb_hist_esus_oci_new';
const chunkSize = 800;

async function fetchTable(pgClient, tableName) {
  const res = await pgClient.query(`SELECT * FROM ${tableName}`);
  return res.rows;
}


function mapPostgresTypeToMySQL(pgType, columnName) {
  switch (pgType) {
    case 20: return 'BIGINT';
    case 23: return 'INT';
    case 21: return 'SMALLINT';
    case 25: return 'TEXT';
    case 1043: return 'VARCHAR(255)';
    case 1114: return 'DATETIME';
    case 1082: return 'DATE';
    case 16: return 'BOOLEAN';
    default: return 'VARCHAR(255)';
  }
}

async function main() {
  let pgClient;
  let mysqlConn;

  try {
    
    pgClient = new Client({
      host: DB_PG_SERVER,
      port: DB_PG_PORT,
      user: DB_PG_USERNAME,
      password: DB_PG_PASSWORD,
      database: DB_PG_NAME,
    });
    await pgClient.connect();

   
    mysqlConn = await mysql.createConnection({
      host: DB_MYSQL_SERVER,
      user: DB_MYSQL_USERNAME,
      password: DB_MYSQL_PASSWORD,
      database: DB_MYSQL_NAME,
    });

    console.log('Carregando tabelas do PostgreSQL...');

    
    const [
      tb_atend_prof,
      tb_atend,
      tb_prontuario,
      tb_cidadao,
      tb_lotacao,
      tb_unidade_saude,
      tb_prof,
      tb_requisicao_exame,
      tb_exame_requisitado,
      tb_proced,
      tb_cid10,
      tb_proced_grupo,
      tb_localidade,
      tb_equipe
    ] = await Promise.all([
      fetchTable(pgClient, 'tb_atend_prof'),
      fetchTable(pgClient, 'tb_atend'),
      fetchTable(pgClient, 'tb_prontuario'),
      fetchTable(pgClient, 'tb_cidadao'),
      fetchTable(pgClient, 'tb_lotacao'),
      fetchTable(pgClient, 'tb_unidade_saude'),
      fetchTable(pgClient, 'tb_prof'),
      fetchTable(pgClient, 'tb_requisicao_exame'),
      fetchTable(pgClient, 'tb_exame_requisitado'),
      fetchTable(pgClient, 'tb_proced'),
      fetchTable(pgClient, 'tb_cid10'),
      fetchTable(pgClient, 'tb_proced_grupo'),
      fetchTable(pgClient, 'tb_localidade'),
      fetchTable(pgClient, 'tb_equipe')
    ]);

    

    
    const mapAtend = new Map(tb_atend.map(a => [a.co_atend_prof, a]));
    const mapPront = new Map(tb_prontuario.map(p => [p.co_seq_prontuario, p]));
    const mapCid = new Map(tb_cidadao.map(c => [c.co_seq_cidadao, c]));
    const mapLotacao = new Map(tb_lotacao.map(l => [l.co_ator_papel, l]));
    const mapUnidade = new Map(tb_unidade_saude.map(u => [u.co_seq_unidade_saude, u]));
    const mapProf = new Map(tb_prof.map(p => [p.co_seq_prof, p]));
    const mapRequisicao = new Map(tb_requisicao_exame.map(r => [r.co_atend_prof, r]));
    const mapExame = new Map(tb_exame_requisitado.map(e => [e.co_requisicao_exame, e]));
    const mapProced = new Map(tb_proced.map(p => [p.co_seq_proced, p]));
    const mapCid10 = new Map(tb_cid10.map(c => [c.co_cid10, c]));
    const mapProcGrupo = new Map(tb_proced_grupo.map(g => [g.co_proced_grupo, g]));
    const mapLocalidade = new Map(tb_localidade.map(l => [l.co_localidade, l]));
    const mapEquipe = new Map(tb_equipe.map(e => [e.co_seq_equipe, e]));

    console.log('Montando dados finais ');

    
    const resultado = tb_atend_prof.map(t1 => {
      const t2 = mapAtend.get(t1.co_seq_atend_prof) || {};
      const t6 = mapPront.get(t2.co_prontuario) || {};
      const t7 = mapCid.get(t6.co_cidadao) || {};
      const t9 = mapLotacao.get(t1.co_lotacao) || {};
      const t11 = mapUnidade.get(t9.co_unidade_saude) || {};
      const t13 = mapProf.get(t9.co_prof) || {};
      const t14 = mapRequisicao.get(t1.co_seq_atend_prof) || {};
      const t15 = mapExame.get(t14.co_seq_requisicao_exame) || {};
      const t16 = mapProced.get(t15.co_proced) || {};
      const t17 = mapCid10.get(t14.co_cid10) || {};
      const t18 = mapProcGrupo.get(t16.co_proced_grupo) || {};
      const t19 = mapLocalidade.get(t7.co_localidade_endereco) || {};
      const t20 = mapEquipe.get(t9.co_equipe) || {};

      
      const no_sexo = t7.no_sexo
        ? t7.no_sexo.toUpperCase() === 'MASCULINO' ? 'M' :
          t7.no_sexo.toUpperCase() === 'FEMININO' ? 'F' : null
        : null;

      const co_ibge = t19.co_ibge ? t19.co_ibge.slice(0,6) || '291920' : '291920';

       return {
        id_atend_esus: t1.co_seq_atend_prof ?? null,
        nu_cpf: t7.nu_cpf ?? null,
        nu_cns: t7.nu_cns ?? null,
        no_cidadao: t7.no_cidadao ?? null,
        dt_nascimento: t7.dt_nascimento ? moment(t7.dt_nascimento).format('YYYY-MM-DD') : null,
        no_mae: t7.no_mae ?? null,
        no_sexo,
        co_ibge,
        ds_cep: t7.ds_cep ?? null,
        ds_logradouro: t7.ds_logradouro ?? null,
        no_bairro: t7.no_bairro ?? null,
        numero_endereco: t7.nu_numero ?? null,
        nu_telefone_celular: t7.nu_telefone_celular ?? null,
        data_atendimento: t1.dt_inicio ? moment(t1.dt_inicio).format('YYYY-MM-DD HH:mm:ss') : null,
        data_requisicao: t14.dt_requisicao ? moment(t14.dt_requisicao).format('YYYY-MM-DD HH:mm:ss') : null,
        ds_justificativa_procedimento: t14.ds_justificativa_procedimento ? t14.ds_justificativa_procedimento.substring(0,255) : null,
        procedimento: t16.no_proced ?? null,
        codigo_sigtap: t16.co_proced ?? null,
        co_cid_justificativa_procedimento: t17.nu_cid10 || 'R69',
        cpf_prof: t13.nu_cpf ?? null,
        cns_prof: t13.nu_cns ?? null,
        nu_cnes: t11.nu_cnes ?? null,
        ine_equipe: t20.nu_ine ?? null,
        nome_equipe: t20.no_equipe ?? null,
        nu_ms: t18.nu_ms ?? null
      };
    }).filter(r => r.no_cidadao && r.codigo_sigtap && r.nu_ms === '09'); 

    if (resultado.length === 0) {
      console.log('Nenhum dado a inserir.');
      return;
    }

   
    
    const fields = Object.keys(resultado[0]);
    const createTableQuery = `CREATE TABLE IF NOT EXISTS ${TABLE_NAME_NEW} (
      ${fields.map(f => `${f} VARCHAR(255)`).join(', ')}
    );`;

    await mysqlConn.execute(createTableQuery);
    await mysqlConn.beginTransaction();

   

    for (let i = 0; i < resultado.length; i += chunkSize) {
      const chunk = resultado.slice(i, i + chunkSize);
      const insertQuery = `INSERT INTO ${TABLE_NAME_NEW} (${fields.join(', ')})
          VALUES ${chunk.map(() => `(${fields.map(() => '?').join(', ')})`).join(', ')}`;
      const values = chunk.flatMap(r => fields.map(f => r[f]));
      await mysqlConn.execute(insertQuery, values);
    }

    await mysqlConn.execute(`DROP TABLE IF EXISTS ${TABLE_NAME}`);
    await mysqlConn.execute(`RENAME TABLE ${TABLE_NAME_NEW} TO ${TABLE_NAME}`);
    await mysqlConn.commit();

    console.log('Operação concluída com sucesso!');

  } catch (error) {
    console.error('Erro:', error);
    if (mysqlConn) await mysqlConn.rollback();
  } finally {
    if (pgClient) await pgClient.end();
    if (mysqlConn) await mysqlConn.end();
  }
}

main();
