using BoredCareers.Entities;
using MySql.Data.MySqlClient;
using System.Data;
using System.Data.Common;

namespace BoredCareers.Services.DatabaseService {
    public partial class DatabaseService {

        public async Task<Resume[]> GetResumes(int AccountID) {
            List<Resume> resumes = new List<Resume>();
            using (MySqlConnection connection = GetConnection()) {
                await connection.OpenAsync();
                string command = @"
                SELECT *
                FROM Resume
                WHERE AccountID = @AccountID;
                ";

                MySqlCommand cmd = new MySqlCommand(command, connection);
                cmd.Parameters.AddWithValue("@AccountID", AccountID);

                using (DbDataReader reader = await cmd.ExecuteReaderAsync()) {
                    while (await reader.ReadAsync()) {
                        if (reader == null) {
                            break;
                        }

                        int _id = reader.GetInt32("ID");
                        int _accountid = reader.GetInt32("AccountID");
                        string _title = reader.GetString("Title");
                        string _name = reader.GetString("Name");
                        string _field = reader.GetString("Field");
                        string _email = reader.GetString("Email");
                        string _phonenumber = reader.GetString("PhoneNumber");
                        string _postalcode = reader.GetString("PostalCode");
                        string _country = reader.GetString("Country");
                        string _state = reader.GetString("StateOrRegion");
                        string _city = reader.GetString("City");
                        bool _isactive = reader.GetBoolean("IsActive");

                        resumes.Add( new Resume() {
                            ID = _id,
                            AccountID = _accountid,
                            Title = _title,
                            Name = _name,
                            Field = _field,
                            Email = _email,
                            PhoneNumber = _phonenumber,
                            PostalCode = _postalcode,
                            Country = _country,
                            StateOrRegion = _state,
                            City = _city,
                            IsActive = _isactive
                        } );
                    }
                }
            }
            return resumes.ToArray();
        }

        public async Task<Resume?> GetResume(int ResumeID) {
            using (var conn = GetConnection()) {
                await conn.OpenAsync();

                // Check if resume header exists
                Resume? resume = await GetResumeHeader(ResumeID);
                if (resume == null) { return null; }

                // Create parallel threads
                Task<ResumeExperience[]> experienceTask = GetResumeExperience(ResumeID);
                Task<ResumeExperienceBullet[]> experienceBulletsTask = GetResumeExperienceBullets(ResumeID);
                Task<ResumeMilitary?> militaryTask = GetResumeMilitary(ResumeID);
                Task<ResumeMilitaryBullet[]> militaryBulletsTask = GetResumeMilitaryBullets(ResumeID);
                Task<ResumeEducation[]> educationTask = GetResumeEducation(ResumeID);
                Task<ResumeSkill[]> skillsTask = GetResumeSkills(ResumeID);
                Task<ResumeLanguage[]> languagesTask = GetResumeLanguages(ResumeID);
                Task<ResumeCertification[]> certificationTask = GetResumeCertification(ResumeID);
                Task<ResumeProject[]> projectsTask = GetResumeProjects(ResumeID);

                // Run all in parallel
                await Task.WhenAll(
                    experienceTask,
                    experienceBulletsTask,
                    militaryTask,
                    militaryBulletsTask,
                    educationTask,
                    skillsTask,
                    languagesTask,
                    certificationTask,
                    projectsTask
                );

                // Get results from parallel processes
                ResumeExperience[] experience = await experienceTask;
                ResumeExperienceBullet[] bullets = await experienceBulletsTask;
                ResumeMilitary? military = await militaryTask;
                ResumeMilitaryBullet[] militaryBullets = await militaryBulletsTask;
                ResumeEducation[] education = await educationTask;
                ResumeSkill[] skills = await skillsTask;
                ResumeLanguage[] languages = await languagesTask;
                ResumeCertification[] certs = await certificationTask;
                ResumeProject[] projects = await projectsTask;

                Dictionary<int, ResumeExperienceBullet[]> groupedExperienceBullets = bullets.GroupBy(b => Convert.ToInt32(b.ResumeExperienceID)).ToDictionary(g => g.Key, g => g.ToArray());
                foreach (var exp in experience) {
                    exp.ExperienceBullets = groupedExperienceBullets.TryGetValue(Convert.ToInt32(exp.ID), out var b) ? b : Array.Empty<ResumeExperienceBullet>();
                }

                resume.Experiences = experience;
                resume.Educations = education;
                resume.Skills = skills;
                resume.Languages = languages;
                resume.Certifications = certs;
                resume.Projects = projects;

                if (military != null) {
                    military.MilitaryBullets = militaryBullets;
                    resume.Military = military;
                }

                return resume;
            }
        }

        public async Task SetResume(Resume resume) {
            // Set ResumeID on all nodes
            int _ResumeID = await SetResumeHeader(resume);
            if (resume.Military != null) {
                resume.Military.ResumeID = _ResumeID;
                foreach (ResumeMilitaryBullet cur in resume.Military.MilitaryBullets) {
                    cur.ResumeID = _ResumeID;
                }
            }
            foreach (ResumeEducation cur in resume.Educations) { cur.ResumeID = _ResumeID; }
            foreach (ResumeSkill cur in resume.Skills) { cur.ResumeID = _ResumeID; }
            foreach (ResumeLanguage cur in resume.Languages) { cur.ResumeID = _ResumeID; }
            foreach (ResumeCertification cur in resume.Certifications) { cur.ResumeID = _ResumeID; }
            foreach (ResumeProject cur in resume.Projects) { cur.ResumeID = _ResumeID; }
            foreach (ResumeExperience cur in resume.Experiences) {
                cur.ResumeID = _ResumeID;
                foreach (ResumeExperienceBullet us in cur.ExperienceBullets) {
                    us.ResumeID = _ResumeID;
                }
            }

            // Async process all non child node SQL sets
            Task[] tasks = [
                SetResumeEducation(resume.Educations),
                SetResumeSkills(resume.Skills),
                SetResumeLanguages(resume.Languages),
                SetResumeCertification(resume.Certifications),
                SetResumeProjects(resume.Projects)
            ];
            await Task.WhenAll(tasks);

            // Setup military task
            if (resume.Military != null) {
                ResumeMilitary militaryTask = await SetResumeMilitary(resume.Military);
                foreach (ResumeMilitaryBullet cur in resume.Military.MilitaryBullets) {
                    cur.ResumeMilitaryID = Convert.ToInt32(militaryTask.ID);
                }
                await SetResumeMilitaryBullets(resume.Military.MilitaryBullets);
            }

            // Setup async process all experience tasks 
            List<Task<ResumeExperience>> experienceTasks = new List<Task<ResumeExperience>>();
            foreach (ResumeExperience cur in resume.Experiences) {
                experienceTasks.Add(SetResumeExperience(cur));
            }
            await Task.WhenAll(experienceTasks);

            // Assuming they are returned in the same order they are sent
            List<Task> experienceBulletTasks = new List<Task>();
            for (int i = 0; i < experienceTasks.Count; i++) {
                ResumeExperience self = await experienceTasks[i];
                foreach (ResumeExperienceBullet cur in resume.Experiences[i].ExperienceBullets) {
                    cur.ResumeExperienceID = Convert.ToInt32(self.ID);
                    experienceBulletTasks.Add(SetResumeExperienceBullets(cur));
                }
            }
            await Task.WhenAll(experienceBulletTasks);
        }

        public async Task DeleteResume( int ResumeID ) {
            using( MySqlConnection connection = GetConnection() ) {
                MySqlCommand cmd;
                connection.Open();

                string command = @"
                DELETE FROM Resume WHERE ID = @ID;
                ";
                cmd = new MySqlCommand( command, connection );
                cmd.Parameters.AddWithValue("@ID", ResumeID);

                await cmd.ExecuteNonQueryAsync();
            }
        }

    }
}
