package main

import (
	"encoding/csv"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"sync"

	"github.com/gocarina/gocsv"
)

type (
	CandidateOld struct {
		IDUsuario             int    `csv:"id_usuario"`
		NMUsuario             string `csv:"nm_usuario"`
		DSSenha               string `csv:"ds_senha"`
		DSEndereco            string `csv:"ds_endereco"`
		NRCep                 string `csv:"nr_cep"`
		IDBairro              string `csv:"id_bairro"`
		DSOutroLocal          string `csv:"ds_outro_local"`
		DSEmail               string `csv:"ds_email"`
		DTNascimento          string `csv:"dt_nascimento"`
		CDSexo                string `csv:"cd_sexo"`
		CDEstadoCivil         string `csv:"cd_estado_civil"`
		NRCPF                 string `csv:"nr_cpf"`
		IDProfissao           string `csv:"id_profissao"`
		SNDeficiente          string `csv:"sn_deficiente"`
		NRTelResidencial      string `csv:"nr_tel_residencial"`
		NRTelCelular          string `csv:"nr_tel_celular"`
		DSFoto                string `csv:"ds_foto"`
		IDCargoObj1           string `csv:"id_cargo_obj1"`
		IDCargoObj2           string `csv:"id_cargo_obj2"`
		IDCargoObj3           string `csv:"id_cargo_obj3"`
		VLSalarioMinAceitavel string `csv:"vl_salario_min_aceitavel"`
		VLSalarioPretendido   string `csv:"vl_salario_pretendido"`
		DSResumoCurriculo     string `csv:"ds_resumo_curriculo"`
		SNExperiencia         string `csv:"sn_experiencia"`
		DTCadastro            string `csv:"dt_cadastro"`
		DTAlteracao           string `csv:"dt_alteracao"`
		SNEmailConfirmado     string `csv:"sn_email_confirmado"`
		SNAtivo               string `csv:"sn_ativo"`
	}
	Candidate struct {
		Id                int    `csv:"id"`
		Name              string `csv:"name"`
		Password          string `csv:"password"`
		Address           string `csv:"address"`
		ZipCode           string `csv:"zip_code"`
		NeighbourhoodID   string `csv:"neighbourhood_id"`
		DSOutroLocal      string `csv:"ds_outro_local"`
		Email             string `csv:"email"`
		BirtDate          string `csv:"birth_date"`
		GenderID          string `csv:"gender_id"`
		CPF               string `csv:"cpf"`
		OccupationID      string `csv:"occupation_id"`
		SpecialNeeds      string `csv:"special_needs"`
		Telephone         string `csv:"telephone"`
		Cellphone         string `csv:"cellphone"`
		Photo             string `csv:"photo"`
		WantedOccupation1 string `csv:"wanted_occupation_1"`
		WantedOccupation2 string `csv:"wanted_occupation_2"`
		WantedOccupation3 string `csv:"wanted_occupation_3"`
		MinPayment        string `csv:"min_payment"`
		DesiredPayment    string `csv:"desired_payment"`
		CVSummary         string `csv:"cv_summary"`
		HasExperience     string `csv:"has_experience"`
		CreatedAt         string `csv:"created_at"`
		UpdatedAt         string `csv:"updated_at"`
		ConfirmedEmail    string `csv:"confirmed_email"`
		Active            string `csv:"active"`
	}
)

func ExecCandidates(wg *sync.WaitGroup) {
	defer wg.Done()

	records := extractCandidatesOld()
	createCandidateCsvs(records)
}

func extractCandidatesOld() []CandidateOld {
	fmt.Println(Yellow + "Extracting candidates" + Reset)
	csvFile, err := os.Open("files/TB_SOPA_BC_PERFIL_USUARIO.csv")
	if err != nil {
		fmt.Println(Red + err.Error() + Reset)
		panic(err)
	}
	defer csvFile.Close()

	reader := csv.NewReader(csvFile)
	reader.Comma = ','

	var records []CandidateOld
	if err := gocsv.UnmarshalCSV(reader, &records); err != nil {
		fmt.Println(Red + err.Error() + Reset)
		panic(err)
	}

	if len(records) == 0 {
		fmt.Println(Red + "No records found" + Reset)
		panic("No records found")
	}

	return records
}

func createCandidateCsvs(records []CandidateOld) {
	maxDataPerFile := 5000
	fileNumber := 1

	runtime.GOMAXPROCS(3)
	var wg sync.WaitGroup

	for start := 0; start < len(records); start += maxDataPerFile {
		end := start + maxDataPerFile
		if end > len(records) {
			end = len(records)
		}

		wg.Add(1)
		go func(fileNumber int, subset []CandidateOld) {
			defer wg.Done()
			writeCandidateCsv(subset, fileNumber)
		}(fileNumber, records[start:end])

		fileNumber++
	}

	wg.Wait()
}

func writeCandidateCsv(records []CandidateOld, fileNumber int) {
	fmt.Println(Yellow + "Creating CSV file number " + fmt.Sprint(fileNumber) + Reset)
	fileName := "candidates" + fmt.Sprint(fileNumber) + ".csv"
	if fileNumber == 1 {
		fileName = "candidates.csv"
	}
	file, err := os.Create(filepath.Join(basePath + fileName))
	if err != nil {
		fmt.Println(Red + err.Error() + Reset)
		panic(err)
	}
	defer file.Close()

	var candidates []*Candidate
	var nullEmails []int
	for _, record := range records {
		if record.DSEmail == "NULL" || record.DSEmail == "" {
			nullEmails = append(nullEmails, record.IDUsuario)
			continue
		}
		if record.IDProfissao != "NULL" {
			occupationIDInt, err := strconv.Atoi(record.IDProfissao)
			if err != nil {
				fmt.Println(Red + err.Error() + Reset)
				panic(err)
			}
			if occupationIDInt > 2874 {
				record.IDProfissao = strconv.Itoa(occupationIDInt - 1)
			}
		}
        if record.IDCargoObj1 != "NULL" {
			occupationIDInt, err := strconv.Atoi(record.IDCargoObj1)
			if err != nil {
				fmt.Println(Red + err.Error() + Reset)
				panic(err)
			}
			if occupationIDInt > 2874 {
				record.IDCargoObj1 = strconv.Itoa(occupationIDInt - 1)
			}
		}
        if record.IDCargoObj2 != "NULL" {
			occupationIDInt, err := strconv.Atoi(record.IDCargoObj2)
			if err != nil {
				fmt.Println(Red + err.Error() + Reset)
				panic(err)
			}
			if occupationIDInt > 2874 {
				record.IDCargoObj2 = strconv.Itoa(occupationIDInt - 1)
			}
		}
        if record.IDCargoObj3 != "NULL" {
			occupationIDInt, err := strconv.Atoi(record.IDCargoObj3)
			if err != nil {
				fmt.Println(Red + err.Error() + Reset)
				panic(err)
			}
			if occupationIDInt > 2874 {
				record.IDCargoObj3 = strconv.Itoa(occupationIDInt - 1)
			}
		}
		cleanedDSResumoCurriculo := replaceCharacter("\r", " ", record.DSResumoCurriculo)
		cleanedDSResumoCurriculo = replaceCharacter("\n", "", cleanedDSResumoCurriculo)
		cleanedDSResumoCurriculo = replaceCharacter("\t", "", cleanedDSResumoCurriculo)
		candidate := &Candidate{
			Id:                record.IDUsuario,
			Name:              record.NMUsuario,
			Password:          record.DSSenha,
			Address:           record.DSEndereco,
			ZipCode:           record.NRCep,
			NeighbourhoodID:   record.IDBairro,
			DSOutroLocal:      record.DSOutroLocal,
			Email:             record.DSEmail,
			BirtDate:          record.DTNascimento,
			GenderID:          record.CDSexo,
			CPF:               record.NRCPF,
			OccupationID:      record.IDProfissao,
			SpecialNeeds:      record.SNDeficiente,
			Telephone:         record.NRTelResidencial,
			Cellphone:         record.NRTelCelular,
			Photo:             record.DSFoto,
			WantedOccupation1: record.IDCargoObj1,
			WantedOccupation2: record.IDCargoObj2,
			WantedOccupation3: record.IDCargoObj3,
			MinPayment:        record.VLSalarioMinAceitavel,
			DesiredPayment:    record.VLSalarioPretendido,
			CVSummary:         cleanedDSResumoCurriculo,
			HasExperience:     record.SNExperiencia,
			CreatedAt:         record.DTCadastro,
			UpdatedAt:         record.DTAlteracao,
			ConfirmedEmail:    record.SNEmailConfirmado,
			Active:            record.SNAtivo,
		}

		candidates = append(candidates, candidate)
	}

	for _, id := range nullEmails {
		fmt.Println(Yellow + "Candidate with ID " + fmt.Sprint(id) + " has no email" + Reset)
	}

	gocsv.SetCSVWriter(func(out io.Writer) *gocsv.SafeCSVWriter {
		writer := csv.NewWriter(out)
		writer.Comma = '\t'
		return gocsv.NewSafeCSVWriter(writer)
	})

	err = gocsv.MarshalFile(&candidates, file)
	if err != nil {
		fmt.Println(Red + err.Error() + Reset)
		panic(err)
	}

	fmt.Println(Green + "Successfully created CSV file number " + fmt.Sprint(fileName) + "with the processed candidates." + Reset)
}
