import { app, BrowserWindow, screen } from 'electron'
import path from 'path'
import { fileURLToPath } from 'url'
import started from 'electron-squirrel-startup'
import express from 'express'
import { Agent } from 'undici'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

const serverApp = express()
const port = 3000

const agent = new Agent({
	connectTimeout: 0,
	headersTimeout: 0,
	bodyTimeout: 0,
})

serverApp.use(express.static(path.join(__dirname, 'public')))
serverApp.use(express.json())

serverApp.get('/', (req, res) => {
	res.sendFile(path.join(__dirname, 'index.html'))
})

const validateCPF = (cpf) => {
	if (!cpf) return false
	cpf = cpf.replace(/\D/g, '')
	if (cpf.length !== 11 || /^(\d)\1+$/.test(cpf)) return false
	const calc = (slice) => ((slice.split('').reduce((sum, num, i) => sum + num * (slice.length + 1 - i), 0) * 10) % 11) % 10
	return calc(cpf.slice(0, 9)) == cpf[9] && calc(cpf.slice(0, 10)) == cpf[10] ? cpf : false
}

let adminCredentials, baseUrl, cookies, userData, cnesUnidades, procedimentosFaturaveis, solicitacoesEmFila

serverApp.post('/login', async (req, res) => {
	adminCredentials = req.body

	baseUrl = `https://www.${adminCredentials.municipio.toString().toLowerCase()}-${adminCredentials.estado.toString().toLowerCase()}`

	const loginVivver = async (login, senha) => {
		const cookiesArr = []
		const cookiesFinal = {}
		try {
			const response = await fetch(`${baseUrl}.vivver.com/login/create`, {
				method: 'POST',
				headers: {
					'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
					Origin: `${baseUrl}.vivver.com`,
					Referer: `${baseUrl}.vivver.com/login?conta=${login}`,
					'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
				},
				body: `utf8=%E2%9C%93&page=&page_query=&conta=${login}&password=${encodeURIComponent(senha)}&commit=Entrar`,
			})

			if (!response.ok) {
				console.log(`Falhou ao logar e pegar os Cookies. Status: ${response.status}`)
				res.json({ errorCode: 1, errorMessage: `Falhou ao logar e pegar os Cookies. Status: ${response.status}` })
				throw new Error()
			}

			console.log(`Logado com sucesso. Checando Perfil...`)

			response.headers
				.get('set-cookie')
				.split(';')
				.forEach((data) => {
					if (data.includes('device') || data.includes('auth') || data.includes('saude') || data.includes('expires')) {
						cookiesArr.push(data)
					}
				})

			cookiesFinal.Device = cookiesArr[0].split('device_id=')[1]
			cookiesFinal.Expires = cookiesArr[1].split('expires_in=')[1]
			cookiesFinal.Auth = cookiesArr[2].split('auth_token=')[1]
			cookiesFinal.VmxSession = cookiesArr[3].split('_vmx_saude_session=')[1]

			return cookiesFinal
		} catch (error) {
			return null
		}
	}

	const checkPerfil = async (cookies) => {
		const operadorID = atob(atob(decodeURIComponent(cookies.Auth.split('--')[0])).split('.')[1]).match(/"seg_operador_id"\s*:\s*(\d+)/)[1]

		try {
			const response = await fetch(`${baseUrl}.vivver.com/seg/operador.json?seg_operador%5Bid%5D=${operadorID}`, {
				method: 'GET',
				headers: {
					cookie: `device_id=${cookies.Device}; auth_token=${cookies.Auth}; expires_in=${cookies.Expires}; _vmx_saude_session=${cookies.VmxSession}`,
					'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
				},
			})

			if (!response.ok) {
				console.log(`Falhou ao identificar o Perfil do Usuário logado: ${response.status}`)
				res.json({ errorCode: 2, errorMessage: `Falhou ao identificar o Perfil do Usuário logado: ${response.status}` })
				throw new Error()
			}

			const perfilOperador = (await response.json()).data[0]['4']

			if (perfilOperador.split(' - ')[1] === 'Administrador') {
				console.log(`Perfil Administrador. Consolidando os dados necessários da Base...`)
				res.status(200).json({ success: true })
			} else {
				console.log(`Perfil do usuário logado não é Administrador. Perfil: ${perfilOperador}`)
				res.json({ errorCode: 3, errorMessage: `Perfil deve ser Administrador. Perfil: ${perfilOperador}` })
				throw new Error()
			}
		} catch (error) {
			return null
		}
	}

	cookies = await loginVivver(adminCredentials.loginCookie, adminCredentials.senhaCookie)

	if (cookies) {
		await checkPerfil(cookies)
	}
})

serverApp.get('/consolidar', async (req, res) => {
	const getUserDocuments = async (cookies) => {
		const dadosPessoais = {}
		try {
			const response = await fetch(`${baseUrl}.vivver.com/amb/paciente.json?start=0&length=9999999`, {
				method: 'GET',
				headers: {
					cookie: `device_id=${cookies.Device}; auth_token=${cookies.Auth}; expires_in=${cookies.Expires}; _vmx_saude_session=${cookies.VmxSession}`,
					'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
				},
				dispatcher: agent,
				keepalive: true,
			})

			if (!response.ok) throw new Error(`Failed to fetch user documents: ${response.status}`)

			const data = (await response.json()).data
			data.forEach((dadoPessoal) => {
				dadosPessoais[`${dadoPessoal['0']}`] = {
					CPF: dadoPessoal['5'] || false,
					CNS: dadoPessoal['6'] || false,
				}
			})

			return dadosPessoais
		} catch (error) {
			console.error(error)
			return null
		}
	}

	const getCnesUnidades = async (cookies) => {
		const unidadesCNES = {}
		try {
			const response = await fetch(`${baseUrl}.vivver.com/adm/unidade_saude.json?start=0&length=9999`, {
				method: 'GET',
				headers: {
					'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
					cookie: `device_id=${cookies.Device}; auth_token=${cookies.Auth}; expires_in=${cookies.Expires}; _vmx_saude_session=${cookies.VmxSession}`,
					'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
				},
			})

			if (!response.ok) throw new Error(`Failed to fetch CNES units: ${response.status}`)

			const data = (await response.json()).data
			data.forEach((unidade) => {
				unidadesCNES[`${unidade['0']}|${unidade['1']}`] = {
					CNES: unidade['3'].toString().length >= 2 ? unidade['3'].toString() : adminCredentials.cnesRegulador,
				}
			})

			return unidadesCNES
		} catch (error) {
			console.error(error)
			return null
		}
	}

	const getFaturaveis = async (cookies) => {
		const procFaturaveis = {}
		try {
			const response = await fetch(
				`${baseUrl}.vivver.com/fwk/lookup_edit_v3?page=1&limit=99999&model=Adm%3A%3AProcedimento&key=codprocedimentofaturavel&name=nomprocedimento&columns=codprocedimento%2Ccodprocedimento`,
				{
					method: 'GET',
					headers: {
						'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
						cookie: `device_id=${cookies.Device}; auth_token=${cookies.Auth}; expires_in=${cookies.Expires}; _vmx_saude_session=${cookies.VmxSession}`,
						'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
					},
				}
			)

			if (!response.ok) throw new Error(`Failed to fetch billable procedures: ${response.status}`)

			const data = (await response.json()).rows
			data.forEach((procedimento) => {
				procFaturaveis[`${procedimento['codprocedimento']}`] = {
					procFaturavel: procedimento['codprocedimentofaturavel'] ? procedimento['codprocedimentofaturavel'].toString() : false,
				}
			})

			return procFaturaveis
		} catch (error) {
			console.error(error)
			return null
		}
	}

	const getFilas = async (cookies) => {
		try {
			const response = await fetch(`${baseUrl}.vivver.com/rams/servico/solicitacao/acompanhamento/fila_espera.json`, {
				method: 'POST',
				headers: {
					'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
					cookie: `device_id=${cookies.Device}; auth_token=${cookies.Auth}; expires_in=${cookies.Expires}; _vmx_saude_session=${cookies.VmxSession}`,
					'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
				},
				body: 'offset=0&limit=100',
				dispatcher: agent,
				keepalive: true,
			})

			if (!response.ok) throw new Error(`Failed to fetch waitlist requests: ${response.status}`)

			const finalData = (await response.json()).rows

			return finalData
		} catch (error) {
			console.error(error)
			return null
		}
	}

	try {
		//prettier-ignore
		[userData, cnesUnidades, procedimentosFaturaveis, solicitacoesEmFila] = await Promise.allSettled([getUserDocuments(cookies), getCnesUnidades(cookies), getFaturaveis(cookies), getFilas(cookies)])

		const failedRequests = []
		if (userData.status === 'rejected') failedRequests.push('Falhou ao pegar os Documentos dos usuários da Base')
		if (cnesUnidades.status === 'rejected') failedRequests.push('Falhou ao listar os CNES das Unidades da Base')
		if (procedimentosFaturaveis.status === 'rejected') failedRequests.push('Falhou ao listar os Procedimentos Faturáveis dos 99 da Base')
		if (solicitacoesEmFila.status === 'rejected') failedRequests.push('Falhou ao listar Solicitações em Fila de Espera da Base')

		if (failedRequests.length > 0) {
			return res.status(500).json({
				errorCode: true,
				errorMessages: failedRequests,
			})
		}

		res.status(200).json({ success: true })
	} catch (error) {
		console.error(error)
		return null
	}
})

serverApp.get('/gerar', async (req, res) => {
	const gerarXLSX = async (userData, solicitacoesEmFila, cnesUnidades, procedimentosFaturaveis) => {
		const dadosPrincipais = []
		const usersSemDocumento = []
		const solicitacoesSemFaturavel = []
		const consultaSemCBOExecutante = []

		solicitacoesEmFila.forEach((solicitacao) => {
			//Usuário sem CPF e sem CNS
			if (!userData[`${solicitacao.numprontuario.toString()}`]?.CPF && !userData[`${solicitacao.numprontuario.toString()}`]?.CNS) {
				usersSemDocumento.push({
					Prontuário: solicitacao.numprontuario.toString(),
					Solicitação: solicitacao.amb_solicitacao_procedimento_servico_id.toString(),
					'Unidade Solicitante': solicitacao.nome_unidade_solicitacao.toString() || '',
					'Unidade Referência': solicitacao.nome_unidade_referencia.toString() || '',
					Telefone: solicitacao.telefone.toString() || '',
				})
				return
			}

			solicitacao.fila_espera.forEach((itemSolicitacao) => {
				let conditionalFlag = false

				//Solicitação não possui um procedimento Faturável
				if (!procedimentosFaturaveis[`${itemSolicitacao.codigo_procedimento.toString()}`]?.procFaturavel) {
					solicitacoesSemFaturavel.push({
						Prontuário: solicitacao.numprontuario.toString(),
						Solicitação: solicitacao.amb_solicitacao_procedimento_servico_id.toString(),
						'Cód. Procedimento': itemSolicitacao.codigo_procedimento.toString() || '',
						'Nome Procedimento': itemSolicitacao.nome_procedimento.toString() || '',
						'Unidade Solicitante': solicitacao.nome_unidade_solicitacao.toString() || '',
						Serviço: solicitacao.servico_tipo_nome.toString().split(' - ')[1],
					})

					conditionalFlag = true
					return
				}

				//Solicitação de Consulta* sem CBO Executante
				if (procedimentosFaturaveis[`${itemSolicitacao.codigo_procedimento.toString()}`].procFaturavel.toString().slice(0, 6) === '030101' && !itemSolicitacao.codigo_especialidade_executante) {
					consultaSemCBOExecutante.push({
						Prontuário: solicitacao.numprontuario.toString(),
						Solicitação: solicitacao.amb_solicitacao_procedimento_servico_id.toString(),
						'Cód. Procedimento': itemSolicitacao.codigo_procedimento.toString() || '',
						'Nome Procedimento': itemSolicitacao.nome_procedimento.toString() || '',
						'Procedimento Faturável': procedimentosFaturaveis[`${itemSolicitacao.codigo_procedimento.toString()}`].procFaturavel.toString() || '',
						Serviço: solicitacao.servico_tipo_nome.toString().split(' - ')[1],
						'Unidade Solicitante': solicitacao.nome_unidade_solicitacao.toString() || '',
					})
					conditionalFlag = true
					return
				}

				if (conditionalFlag) return

				dadosPrincipais.push({
					identificador_local: solicitacao.amb_solicitacao_procedimento_servico_id.toString(),
					documento_paciente: validateCPF(userData[`${solicitacao.numprontuario.toString()}`].CPF)
						? userData[`${solicitacao.numprontuario.toString()}`].CPF
						: userData[`${solicitacao.numprontuario.toString()}`].CNS,
					data_solicitacao: `${solicitacao.data_hora_solicitacao.split(' ')[0].split('/')[2]}-${solicitacao.data_hora_solicitacao.split(' ')[0].split('/')[1]}-${
						solicitacao.data_hora_solicitacao.split(' ')[0].split('/')[0]
					}`,
					cnes_solicitante: cnesUnidades[`${solicitacao.codigo_municipio_solicitacao}|${solicitacao.codigo_unidade_solicitacao}`].CNES,
					cnes_regulador: adminCredentials.cnesRegulador,
					codigo_sigtap: procedimentosFaturaveis[`${itemSolicitacao.codigo_procedimento.toString()}`].procFaturavel,
					cbo: itemSolicitacao.codigo_especialidade_executante ? itemSolicitacao.codigo_especialidade_executante.toString() : '',
					cid10: itemSolicitacao.codigo_cid ? itemSolicitacao.codigo_cid.toString() : '',
					codigo_modalidade_assistencial: '07',
					codigo_carter_solicitacao: '1',
					status: '1',
					data_autorizacao: '',
					data_execucao: '',
					cnes_executante: '',
				})
			})
		})

		console.log('Dados consolidados. Enviando para o Front-End...')

		res.status(200).json({ success: true, dados: [dadosPrincipais, usersSemDocumento, solicitacoesSemFaturavel, consultaSemCBOExecutante] })
	}

	await gerarXLSX(userData.value, solicitacoesEmFila.value, cnesUnidades.value, procedimentosFaturaveis.value)

	console.log('Finalizado.')
})

function startExpressServer() {
	serverApp.listen(port, () => {
		console.log(`Server running at http://localhost:${port}`)
	})
}

let mainWindow

if (started) {
	app.quit()
}

app.whenReady().then(() => {
	startExpressServer()

	const { width, height } = screen.getPrimaryDisplay().workAreaSize // Get screen height and width

	const windowWidth = width * 0.8
	const windowHeight = windowWidth * (9 / 16)

	mainWindow = new BrowserWindow({
		width: windowWidth,
		height: windowHeight,
		webPreferences: {
			nodeIntegration: true,
			contextIsolation: false,
		},
	})

	mainWindow.loadURL(`http://localhost:${port}`)

	mainWindow.on('closed', () => {
		mainWindow = null
	})
})

app.on('window-all-closed', () => {
	if (process.platform !== 'darwin') {
		app.quit()
	}
})
