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

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

        public async Task<JobListing[]> GetJobListingPage(int PageNumber, int CountPerPage, string[]? PostalCodes = null, string? CountryCode = null, string? JobType = null, bool? Remote = null, int? SalaryMin = null, int? SalaryMax = null ) {
            List<JobListing> joblistings = new List<JobListing>();
            using (MySqlConnection connection = GetConnection()) {
                await connection.OpenAsync();

                string select = "SELECT * FROM JobListing";
                string order = " ORDER BY CreatedTime DESC";
                string limit = " LIMIT @PageSize OFFSET @PageNumber;";

                List<string> Filters = new List<string>();
                List<object> Parameters = new List<object>();
                List<string> ParameterName = new List<string>();

                if (PostalCodes != null) {
                    for (int i = 0; i < PostalCodes.Length; i++) {
                        Filters.Add("PostalCode");
                        Parameters.Add(PostalCodes[i]);
                        ParameterName.Add(" = @PostalCode" + i);
                    }
                }

                if (CountryCode != null) {
                    Filters.Add("Country");
                    Parameters.Add(CountryCode);
                    ParameterName.Add(" = @CountryCode");
                }

                if (JobType != null) {
                    Filters.Add("JobType");
                    Parameters.Add(JobType);
                    ParameterName.Add(" = @JobType");
                }

                if (Remote != null) {
                    Filters.Add("Remote");
                    Parameters.Add(Remote.Value);
                    ParameterName.Add(" = @Remote");
                }

                if (SalaryMin != null) {
                    Filters.Add("SalaryMin");
                    Parameters.Add(SalaryMin.Value);
                    ParameterName.Add(" >= @SalaryMin");
                }

                if (SalaryMax != null) {
                    Filters.Add("SalaryMax");
                    Parameters.Add(SalaryMax.Value);
                    ParameterName.Add(" <= @SalaryMax");
                }

                string filter = " WHERE IsDeleted = False";
                for (int i = 0; i < Filters.Count; i++) {
                    if (Filters[i] == "PostalCode" && i != 0) {
                        filter += " OR ";
                    } else {
                        filter += " AND ";
                    }
                    filter += Filters[i] + ParameterName[i];
                }

                MySqlCommand cmd = new MySqlCommand(select + filter + order + limit, connection);
                cmd.Parameters.AddWithValue("@PageSize", CountPerPage);
                cmd.Parameters.AddWithValue("@PageNumber", (PageNumber - 1) * CountPerPage);
                for (int i = 0; i < Filters.Count; i++) {
                    cmd.Parameters.AddWithValue( ParameterName[i].Split(' ').Last(), Parameters[i] );
                }

                using (DbDataReader reader = await cmd.ExecuteReaderAsync()) {
                    while (await reader.ReadAsync()) {
                        int _id = reader.GetInt32("ID");
                        int _companyid = reader.GetInt32("CompanyID");
                        string _title = reader.GetString("Title");
                        string _postalcode = reader.GetString("PostalCode");
                        string _country = reader.GetString("Country");
                        string _state = reader.GetString("StateOrRegion");
                        string _city = reader.GetString("City");
                        int _salarymin = reader.GetInt32("SalaryMin");
                        int _salarymax = reader.GetInt32("SalaryMax");
                        string _jobtype = reader.GetString("JobType");
                        bool _remote = reader.GetBoolean("Remote");
                        string _description = reader.GetString("Description");
                        JobListingSkill[] _skills = await GetJobListingSkills(_id);
                        DateTime _createtime = reader.GetDateTime("CreatedTime");
                        DateTime _modifiedtime = reader.GetDateTime("ModifiedTime");
                        bool _isdeleted = reader.GetBoolean("IsDeleted");

                        joblistings.Add(new JobListing() {
                            ID = _id,
                            CompanyID = _companyid,
                            Title = _title,
                            PostalCode = _postalcode,
                            Country = _country,
                            StateOrRegion = _state,
                            City = _city,
                            SalaryMin = _salarymin,
                            SalaryMax = _salarymax,
                            JobType = _jobtype,
                            Remote = _remote,
                            Description = _description,
                            Skills = _skills,
                            CreatedTime = _createtime,
                            ModifiedTime = _modifiedtime,
                            IsDeleted = _isdeleted
                        });
                    }
                }
            }
            return joblistings.ToArray();
        }

        public async Task<JobListing[]> GetJobListingFromCompany(int CompanyID) {
            List<JobListing> joblistings = new List<JobListing>(); ;
            using (MySqlConnection connection = GetConnection()) {
                await connection.OpenAsync();
                string command = @"
                SELECT *
                FROM JobListing
                WHERE IsDeleted = FALSE
                AND CompanyID = @CompanyID;
                ";

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

                using (DbDataReader reader = await cmd.ExecuteReaderAsync()) {
                    while (await reader.ReadAsync()) {
                        int _id = reader.GetInt32("ID");
                        int _companyid = reader.GetInt32("CompanyID");
                        string _title = reader.GetString("Title");
                        string _postalcode = reader.GetString("PostalCode");
                        string _country = reader.GetString("Country");
                        string _state = reader.GetString("StateOrRegion");
                        string _city = reader.GetString("City");
                        int _salarymin = reader.GetInt32("SalaryMin");
                        int _salarymax = reader.GetInt32("SalaryMax");
                        string _jobtype = reader.GetString("JobType");
                        bool _remote = reader.GetBoolean("Remote");
                        string _description = reader.GetString("Description");
                        JobListingSkill[] _skills = await GetJobListingSkills(_id);
                        DateTime _createtime = reader.GetDateTime("CreatedTime");
                        DateTime _modifiedtime = reader.GetDateTime("ModifiedTime");
                        bool _isdeleted = reader.GetBoolean("IsDeleted");

                        joblistings.Add(new JobListing() {
                            ID = _id,
                            CompanyID = _companyid,
                            Title = _title,
                            PostalCode = _postalcode,
                            Country = _country,
                            StateOrRegion = _state,
                            City = _city,
                            SalaryMin = _salarymin,
                            SalaryMax = _salarymax,
                            JobType = _jobtype,
                            Remote = _remote,
                            Description = _description,
                            Skills = _skills,
                            CreatedTime = _createtime,
                            ModifiedTime = _modifiedtime,
                            IsDeleted = _isdeleted
                        });
                    }
                }
            }
            return joblistings.ToArray();
        }

        public async Task<JobListing?> GetJobListing(int JobListingID) {
            JobListing? joblisting = null;
            using (MySqlConnection connection = GetConnection()) {
                await connection.OpenAsync();
                string command = @"
                SELECT *
                FROM JobListing
                WHERE ID = @ID;
                ";

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

                using (DbDataReader reader = await cmd.ExecuteReaderAsync()) {
                    while (await reader.ReadAsync()) {
                        int _id = reader.GetInt32("ID");
                        int _companyid = reader.GetInt32("CompanyID");
                        string _title = reader.GetString("Title");
                        string _postalcode = reader.GetString("PostalCode");
                        string _country = reader.GetString("Country");
                        string _state = reader.GetString("StateOrRegion");
                        string _city = reader.GetString("City");
                        int _salarymin = reader.GetInt32("SalaryMin");
                        int _salarymax = reader.GetInt32("SalaryMax");
                        string _jobtype = reader.GetString("JobType");
                        bool _remote = reader.GetBoolean("Remote");
                        string _description = reader.GetString("Description");
                        JobListingSkill[] _skills = await GetJobListingSkills(_id);
                        DateTime _createtime = reader.GetDateTime("CreatedTime");
                        DateTime _modifiedtime = reader.GetDateTime("ModifiedTime");
                        bool _isdeleted = reader.GetBoolean("IsDeleted");

                        joblisting = new JobListing() {
                            ID = _id,
                            CompanyID = _companyid,
                            Title = _title,
                            PostalCode = _postalcode,
                            Country = _country,
                            StateOrRegion = _state,
                            City = _city,
                            SalaryMin = _salarymin,
                            SalaryMax = _salarymax,
                            JobType = _jobtype,
                            Remote = _remote,
                            Description = _description,
                            Skills = _skills,
                            CreatedTime = _createtime,
                            ModifiedTime = _modifiedtime,
                            IsDeleted = _isdeleted
                        };
                    }
                }
            }
            return joblisting;
        }

        public async Task<JobListingDTO[]> GetJobListingsPastExipre() {
            List<JobListingDTO> joblistings = new List<JobListingDTO>();
            using (MySqlConnection connection = GetConnection()) {
                await connection.OpenAsync();
                string command = @"
                SELECT ID, CompanyID
                FROM JobListing
                WHERE IsDeleted = FALSE
                AND CreatedTime < NOW() - INTERVAL 1 MONTH;
                ";
                MySqlCommand cmd = new MySqlCommand(command, connection);

                using (DbDataReader reader = await cmd.ExecuteReaderAsync()) {
                    while (await reader.ReadAsync()) {
                        int _id = reader.GetInt32("ID");
                        int _companyid = reader.GetInt32("CompanyID");
                        joblistings.Add(new JobListingDTO() {
                            JobListingID = _id,
                            CompanyID = _companyid
                        });
                    }
                }
            }
            return joblistings.ToArray();
        }

        public async Task SetJobListing(JobListing jobListing) {
            using (MySqlConnection connection = GetConnection()) {
                await connection.OpenAsync();

                string command = @"
                INSERT INTO JobListing
                (ID,CompanyID,Title,PostalCode,Country,StateOrRegion,City,SalaryMin,SalaryMax,JobType,Remote,Description,CreatedTime,ModifiedTime,IsDeleted)
                VALUES
                (@ID,@CompanyID,@Title,@PostalCode,@Country,@StateOrRegion,@City,@SalaryMin,@SalaryMax,@JobType,@Remote,@Description,@CreatedTime,@ModifiedTime,@IsDeleted)
                ON DUPLICATE KEY UPDATE
                CompanyID = @CompanyID,
                Title = @Title,
                PostalCode = @PostalCode,
                Country = @Country,
                StateOrRegion = @StateOrRegion,
                City = @City,
                SalaryMin = @SalaryMin,
                SalaryMax = @SalaryMax,
                JobType = @JobType,
                Remote = @Remote,
                Description = @Description,
                ModifiedTime = @ModifiedTime,
                IsDeleted = @IsDeleted;

                SELECT LAST_INSERT_ID();
                ";

                MySqlCommand cmd = new MySqlCommand(command, connection);
                cmd.Parameters.AddWithValue("@ID", jobListing.ID);
                cmd.Parameters.AddWithValue("@CompanyID", jobListing.CompanyID);
                cmd.Parameters.AddWithValue("@Title", jobListing.Title);
                cmd.Parameters.AddWithValue("@PostalCode", jobListing.PostalCode);
                cmd.Parameters.AddWithValue("@Country", jobListing.Country);
                cmd.Parameters.AddWithValue("@StateOrRegion", jobListing.StateOrRegion);
                cmd.Parameters.AddWithValue("@City", jobListing.City);
                cmd.Parameters.AddWithValue("@SalaryMin", jobListing.SalaryMin);
                cmd.Parameters.AddWithValue("@SalaryMax", jobListing.SalaryMax);
                cmd.Parameters.AddWithValue("@JobType", jobListing.JobType);
                cmd.Parameters.AddWithValue("@Remote", jobListing.Remote);
                cmd.Parameters.AddWithValue("@Description", jobListing.Description);
                cmd.Parameters.AddWithValue("@CreatedTime", DateTime.UtcNow);
                cmd.Parameters.AddWithValue("@ModifiedTime", DateTime.UtcNow);
                cmd.Parameters.AddWithValue("@IsDeleted", jobListing.IsDeleted);

                object? result = await cmd.ExecuteScalarAsync();
                int jobListingID = 0;
                if (jobListing.ID != null && jobListing.ID != 0) {
                    jobListingID = Convert.ToInt32(jobListing.ID);
                } else {
                    cmd.CommandText = "";
                    jobListingID = Convert.ToInt32(result);
                }

                foreach (JobListingSkill cur in jobListing.Skills) {
                    cur.JobListingID = jobListingID;
                    await SetJobListingSkills(cur);
                }
            }
        }
        
        public async Task DeleteJobListingsPastExipre() {
            using (MySqlConnection connection = GetConnection()) {
                await connection.OpenAsync();
                string command = @"
                UPDATE JobListing
                SET IsDeleted = TRUE
                WHERE IsDeleted = FALSE
                AND CreatedTime < NOW() - INTERVAL 1 MONTH;
                ";
                MySqlCommand cmd = new MySqlCommand(command, connection);
                await cmd.ExecuteNonQueryAsync();
            }
        }

        public async Task DeleteJobListing(int JobListingID) {
            using (MySqlConnection connection = GetConnection()) {
                MySqlCommand cmd;
                await connection.OpenAsync();

                string command = @"
                UPDATE JobListing
                SET IsDeleted = TRUE
                WHERE ID = @ID;
                ";
                cmd = new MySqlCommand(command, connection);
                cmd.Parameters.AddWithValue("@ID", JobListingID);

                await cmd.ExecuteNonQueryAsync();
            }
        }

    }
}
