using CityInfo.API.DbContexts;
using CityInfo.API.Entities;
using Microsoft.EntityFrameworkCore;

namespace CityInfo.API.Services
{
    public class CityInfoRepository : ICityInfoRepository
    {
        private CityInfoContext _context;
        public CityInfoRepository(CityInfoContext context)
        {
            _context = context ?? throw new ArgumentNullException(nameof(CityInfoContext));
        }
        public async Task<IEnumerable<City>> GetCitiesAsync()
        {
            return await _context.Cities.OrderBy((city) => city.Name).ToListAsync();
        }
        public async Task<(IEnumerable<City>, PaginationMetadata)> GetCitiesAsync(string? name, string? searchQuery, int pageNumber, int pageSize)
        {
            var collection = _context.Cities as IQueryable<City>;

            if (!string.IsNullOrEmpty(name))
            {
                name = name.Trim();
                collection = collection.Where((city) => city.Name == name);
            }

            if (!string.IsNullOrEmpty(searchQuery))
            {
                searchQuery = searchQuery.Trim();
                collection = collection.Where(
                    (city) => (
                        city.Name.Contains(searchQuery) |
                        (city.Description != null && city.Description.Contains(searchQuery))
                    )
                );
            }
            var totalItemCount = await collection.CountAsync();
            var paginationMetaData = new PaginationMetadata(totalItemCount, pageSize, pageNumber);
            var collectionToReturn = await collection
                .OrderBy((city) => city.Name)
                .Skip(pageSize * (pageNumber - 1))
                .Take(pageSize)
                .ToListAsync();

            return (collectionToReturn, paginationMetaData);
        }

        public async Task<City?> GetCityAsync(int cityId, bool includePointsOfinterest)
        {
            if (includePointsOfinterest)
            {
                return await _context.Cities
                    .Include((city) => city.PointsOfInterest)
                    .Where((city) => city.Id == cityId)
                    .FirstOrDefaultAsync();
            }
            return await _context.Cities
                    .Where((city) => city.Id == cityId)
                    .FirstOrDefaultAsync();
        }

        public async Task<bool> CityExistAsync(int cityId)
        {
            return await _context.Cities.AnyAsync((city) => city.Id == cityId);
        }

        public async Task<IEnumerable<PointOfInterest>> GetPointsOfinterestForCityAsync(int cityId)
        {
            return await _context.PointsOfInterest.Where((poi) => poi.CityId == cityId).ToListAsync();
        }

        public async Task<PointOfInterest?> GetPointOfInterestForCityAsync(int cityId, int pointOfInterestId)
        {
            return await _context.PointsOfInterest.Where((poi) => poi.CityId == cityId && poi.Id == pointOfInterestId).FirstOrDefaultAsync();
        }

        public async Task CreatePointOfInterestForCityAsync(int cityId, PointOfInterest pointOfInterest)
        {
            var city = await GetCityAsync(cityId, includePointsOfinterest: false);
            if (city != null)
            {
                city.PointsOfInterest.Add(pointOfInterest);
            }
        }
        public async Task<bool> SaveChangesAsync()
        {
           return (await _context.SaveChangesAsync() >= 0);
        }
        public void DeletePointOfInterest(PointOfInterest pointOfInterest)
        {
            _context.PointsOfInterest.Remove(pointOfInterest);
        }

        public async Task<bool> CityNameMatchesCityId(string? cityName, int cityId)
        {
            return await _context.Cities.AnyAsync((city) => city.Name == cityName && city.Id == cityId);
        }

    }
}
