using System;
using System.Collections.Generic;
using System.Linq;
using Npgsql;
using Dapper;
using АвтотранспортноеПредприятие.Models;
using АвтотранспортноеПредприятие.Models.АвтотранспортноеПредприятие.Models;

namespace АвтотранспортноеПредприятие.Database
{
    public class DatabaseManager
    {
        private string connectionString = "Host=edu-pg.itiscaf.ru;Port=5432;Database=dbwork;Username=isupov_ta;Password=CzNY%b&z%$Z";

        public NpgsqlConnection GetConnection()
        {
            return new NpgsqlConnection(connectionString);
        }

        public Customer Authenticate(string phone, string password)
        {
            using var conn = GetConnection();
            string sql = "SELECT customer_id, last_name, first_name, middle_name, phone, password, role FROM customer WHERE phone = @phone AND password = @password";
            var user = conn.QueryFirstOrDefault<Customer>(sql, new { phone = phone, password = password });
            return user;
        }

        public List<Customer> GetAllCustomers()
        {
            using var conn = GetConnection();
            string sql = "SELECT customer_id, last_name, first_name, middle_name, phone, password, role FROM customer ORDER BY last_name, first_name";
            return conn.Query<Customer>(sql).ToList();
        }

        public List<Garage> GetAllGarages()
        {
            using var conn = GetConnection();
            string sql = "SELECT garage_id, garage_number, address_id, manager_id FROM garage ORDER BY garage_number";
            return conn.Query<Garage>(sql).ToList();
        }

        public List<DriverInfo> GetAllDriversInfo()
        {
            using var conn = GetConnection();
            string sql = "SELECT full_name, emp_position, driver_license, license_category, garage_number, garage_address, license_plate, model_name, manufacturer FROM driverinfo";
            return conn.Query<DriverInfo>(sql).ToList();
        }

        public List<DriverInfo> GetDriversByGarageNumber(int garageNumber)
        {
            using var conn = GetConnection();
            string sql = "SELECT full_name, emp_position, driver_license, license_category FROM getDriversByGarage(@garagenum)";
            var result = conn.Query<DriverInfo>(sql, new { garagenum = garageNumber }).ToList();
            return result;
        }

        public List<Employee> GetAllEmployees()
        {
            using var conn = GetConnection();
            string sql = @"SELECT employee_id, last_name, first_name, middle_name, emp_position, phone, 
                          birth_date::text as birth_date, 
                          hire_date::text as hire_date, 
                          passport 
                   FROM employee ORDER BY last_name, first_name";
            return conn.Query<Employee>(sql).ToList();
        }

        public int AddEmployee(Employee employee)
        {
            using var conn = GetConnection();
            string sql = @"INSERT INTO employee (last_name, first_name, middle_name, emp_position, phone, birth_date, hire_date, passport) 
                           VALUES (@last_name, @first_name, @middle_name, @emp_position, @phone, @birth_date, @hire_date, @passport)
                           RETURNING employee_id";
            return conn.ExecuteScalar<int>(sql, employee);
        }

        public bool UpdateEmployee(Employee employee)
        {
            using var conn = GetConnection();
            string sql = @"UPDATE employee SET 
                           last_name = @last_name, 
                           first_name = @first_name, 
                           middle_name = @middle_name,
                           emp_position = @emp_position, 
                           phone = @phone, 
                           birth_date = @birth_date, 
                           hire_date = @hire_date, 
                           passport = @passport
                           WHERE employee_id = @employee_id";
            return conn.Execute(sql, employee) > 0;
        }

        public bool DeleteEmployee(int employeeId)
        {
            using var conn = GetConnection();
            string sql = "DELETE FROM employee WHERE employee_id = @employee_id";
            return conn.Execute(sql, new { employee_id = employeeId }) > 0;
        }

        public List<Vehicle> GetAllVehicles()
        {
            using var conn = GetConnection();
            string sql = @"SELECT v.license_plate, v.engine_number, v.model_id, v.garage_id, cm.model_name, cm.manufacturer 
                           FROM vehicle v
                           LEFT JOIN carmodel cm ON v.model_id = cm.model_id
                           ORDER BY v.license_plate";
            return conn.Query<Vehicle>(sql).ToList();
        }

        public List<Order> GetAllOrders()
        {
            using var conn = GetConnection();
            string sql = @"SELECT o.order_id, 
                                   o.created_date::text as created_date, 
                                   o.status, 
                                   o.pickup_datetime::text as pickup_datetime, 
                                   o.customer_id, 
                                   o.pickup_address_id, 
                                   o.destination_address_id,
                                   o.license_plate, 
                                   o.driver_id, 
                                   o.description,
                                   c.last_name || ' ' || c.first_name as customer_name,
                                   e.last_name || ' ' || e.first_name as driver_name,
                                   a1.city || ', ' || a1.street || ', ' || a1.house_number as pickup_address,
                                   a2.city || ', ' || a2.street || ', ' || a2.house_number as destination_address
                                   FROM orders o
                                   LEFT JOIN customer c ON o.customer_id = c.customer_id
                                   LEFT JOIN driver d ON o.driver_id = d.driver_id
                                   LEFT JOIN employee e ON d.employee_id = e.employee_id
                                   LEFT JOIN address a1 ON o.pickup_address_id = a1.address_id
                                   LEFT JOIN address a2 ON o.destination_address_id = a2.address_id
                                   ORDER BY o.created_date DESC";
            return conn.Query<Order>(sql).ToList();
        }

        public List<Order> GetOrdersByCustomerId(int customerId)
        {
            using var conn = GetConnection();
            string sql = @"SELECT o.order_id, 
                                   o.created_date::text as created_date, 
                                   o.status, 
                                   o.pickup_datetime::text as pickup_datetime, 
                                   o.customer_id, 
                                   o.pickup_address_id, 
                                   o.destination_address_id,
                                   o.license_plate, 
                                   o.driver_id, 
                                   o.description,
                                   c.last_name || ' ' || c.first_name as customer_name,
                                   e.last_name || ' ' || e.first_name as driver_name,
                                   a1.city || ', ' || a1.street || ', ' || a1.house_number as pickup_address,
                                   a2.city || ', ' || a2.street || ', ' || a2.house_number as destination_address
                                   FROM orders o
                                   INNER JOIN customer c ON o.customer_id = c.customer_id
                                   LEFT JOIN driver d ON o.driver_id = d.driver_id
                                   LEFT JOIN employee e ON d.employee_id = e.employee_id
                                   LEFT JOIN address a1 ON o.pickup_address_id = a1.address_id
                                   LEFT JOIN address a2 ON o.destination_address_id = a2.address_id
                                   WHERE c.customer_id = @customerId
                                   ORDER BY o.created_date DESC";
            return conn.Query<Order>(sql, new { customerId = customerId }).ToList();
        }

        public int GetCustomerIdByPhone(string phone)
        {
            using var conn = GetConnection();
            string sql = "SELECT customer_id FROM customer WHERE phone = @phone";
            return conn.ExecuteScalar<int>(sql, new { phone = phone });
        }

        public int AddOrder(Order order)
        {
            using var conn = GetConnection();
            string sql = @"INSERT INTO orders (created_date, status, pickup_datetime, 
                           customer_id, pickup_address_id, destination_address_id,
                           license_plate, driver_id, description) 
                   VALUES (CURRENT_DATE, @status, @pickup_datetime, 
                           @customer_id, @pickup_address_id, @destination_address_id,
                           @license_plate, @driver_id, @description)
                   RETURNING order_id";
            return conn.ExecuteScalar<int>(sql, order);
        }

        public bool UpdateOrder(Order order)
        {
            using var conn = GetConnection();
            string sql = @"UPDATE orders SET 
                           status = @status,
                           pickup_datetime = @pickup_datetime::timestamp,
                           pickup_address_id = @pickup_address_id,
                           destination_address_id = @destination_address_id,
                           license_plate = @license_plate,
                           driver_id = @driver_id,
                           description = @description
                           WHERE order_id = @order_id";
            return conn.Execute(sql, order) > 0;
        }

        public bool DeleteOrder(int orderId)
        {
            using var conn = GetConnection();
            string sql = "DELETE FROM orders WHERE order_id = @order_id";
            return conn.Execute(sql, new { order_id = orderId }) > 0;
        }
        public List<Address> GetAllAddressesForOrder()
        {
            using var conn = GetConnection();
            string sql = "SELECT address_id, city, street, house_number, building FROM address ORDER BY city, street";
            return conn.Query<Address>(sql).ToList();
        }
        public List<Driver> GetAllDrivers()
        {
            using var conn = GetConnection();
            string sql = @"SELECT d.driver_id, d.employee_id, d.driver_license, d.license_category, d.garage_id,
                          e.last_name || ' ' || e.first_name as FullName
                   FROM driver d
                   LEFT JOIN employee e ON d.employee_id = e.employee_id";
            return conn.Query<Driver>(sql).ToList();
        }
       

        public List<Vehicle> GetAllVehiclesForOrder()
        {
            using var conn = GetConnection();
            string sql = "SELECT license_plate, engine_number, model_id, garage_id FROM vehicle";
            return conn.Query<Vehicle>(sql).ToList();
        }

       

        public List<Address> GetAllAddresses()
        {
            using var conn = GetConnection();
            string sql = "SELECT address_id, city, street, house_number, building FROM address ORDER BY address_id";
            return conn.Query<Address>(sql).ToList();
        }

        public List<CarModel> GetAllCarModels()
        {
            using var conn = GetConnection();
            string sql = "SELECT model_id, model_name, manufacturer, body_type, car_class FROM carmodel ORDER BY model_id";
            return conn.Query<CarModel>(sql).ToList();
        }
    }
}