using System.Linq.Expressions;
using adas_core.Domain.Models.Filter;
using Microsoft.EntityFrameworkCore;

namespace adas_core.Domain;

public interface IDefaultRepository<T, in TS> where T : class
{
    /// <summary>
    /// Returns the <see cref="DbSet{T}"/> for entity type <typeparamref name="T"/>, enabling querying and persistence operations against the corresponding table.
    /// </summary>
    /// <returns>A <see cref="DbSet{T}"/> instance for the entity type <typeparamref name="T"/>.</returns>
    DbSet<T> GetSet();
    /// <summary>
    /// Gets an <see cref="IQueryable{T}"/> representing the queryable source of items, allowing callers to compose additional query operations.
    /// </summary>
    /// <returns>An <see cref="IQueryable{T}"/> that can be used to build and execute queries against the underlying data source.</returns>
    IQueryable<T> Query();
    /// <summary>
    /// Returns a queryable collection of <typeparamref name="T"/> items, optionally applying the specified pagination filter to control paging behavior.
    /// </summary>
    /// <param name="filter">The pagination filter that controls paging of the returned items, or <c>null</c> to omit pagination.</param>
    /// <returns>An <see cref="IQueryable{T}"/> that can be used to enumerate the items with the applied filter.</returns>
    IQueryable<T> Query(PaginationFilter? filter);
    /// <summary>
    /// Returns a paginated queryable sequence of items based on the specified page and page size.
    /// </summary>
    /// <param name="currentPage">The current page number; when null, pagination may be ignored or handled accordingly.</param>
    /// <param name="pageSize">The number of items per page; when null, a default page size may be used.</param>
    /// <returns>An <see cref="IQueryable{T}"/> representing the requested page of items.</returns>
    IQueryable<T> Query(int? currentPage, int? pageSize = null);

    /// <summary>
    /// Retrieves an entity of type <typeparamref name="T"/> by its identifier, optionally eager-loading related entities via the provided include expressions.
    /// </summary>
    /// <param name="id">The identifier of the entity to look up.</param>
    /// <param name="includeExpressions">Expressions that specify related entities to include in the returned result.</param>
    /// <returns>The entity matching the supplied identifier, or <c>null</c> if no entity is found.</returns>
    T? GetById(TS id, params Expression<Func<T, object>>[] includeExpressions);

    /// <summary>
    /// Retrieves an entity of type <typeparamref name="T"/> by its identifier, returning <c>null</c> when no matching record is found.
    /// The lookup is performed using the provided <see cref="QueryCustomizer{T}"/> to allow caller-specific query adjustments such as includes, filters, or tracking settings.
    /// </summary>
    /// <param name="id">The identifier of type <typeparamref name="TS"/> used to locate the entity.</param>
    /// <param name="queryCustomizer">A customizer that controls how the underlying query is constructed and executed.</param>
    /// <returns>The matching entity of type <typeparamref name="T"/>, or <c>null</c> if no entity with the given <paramref name="id"/> is found.</returns>
    T? GetById(TS id, QueryCustomizer<T> queryCustomizer);

    /*[Obsolete("Use GetById(<S> id) instead")]
    T? GetById(int id);
    [Obsolete("Use GetById(<S> id) instead")]
    T? GetById(long id);
    //T? GetById(string id);*/
    /// <summary>
    /// Retrieves an entity of type <typeparamref name="T"/> by its composite key values, returning <c>null</c> if no matching entity is found.
    /// </summary>
    /// <param name="keyValues">The values that compose the primary key of the entity to retrieve.</param>
    /// <returns>The matching entity of type <typeparamref name="T"/>, or <c>null</c> if no entity is found.</returns>
    T? GetByIds(params object[] keyValues);
    /// <summary>
    /// Creates a new instance of type T based on the specified source object.
    /// </summary>
    /// <param name="obj">The source object used to create the new instance.</param>
    /// <returns>A new instance of type T created from the specified object.</returns>
    T Create(T obj);
    /// <summary>
    /// Creates a list of objects based on the provided collection of input items.
    /// </summary>
    /// <param name="objs">The list of input objects to be created.</param>
    /// <returns>A list of created objects of type <typeparamref name="T"/>.</returns>
    List<T> Create(List<T> objs);
    /// <summary>
    /// Deletes the specified object from the underlying data source and returns the result.
    /// </summary>
    /// <param name="obj">The object of type <typeparamref name="T"/> to be deleted.</param>
    /// <returns>The object of type <typeparamref name="T"/> representing the result of the delete operation.</returns>
    T Delete(T obj);
    /// <summary>
    /// Deletes the specified collection of objects.
    /// </summary>
    /// <param name="objs">The collection of objects to delete.</param>
    /// <returns>A list of the deleted objects.</returns>
    List<T> Delete(ICollection<T> objs);
    /// <summary>
    /// Deletes all records or entries managed by the associated repository or service.
    /// </summary>
    void DeleteAll();
    /// <summary>
    /// Updates the specified entity in the underlying store and returns the updated instance.
    /// </summary>
    /// <param name="obj">The entity instance containing the updated values to persist.</param>
    /// <returns>The updated entity of type <typeparamref name="T"/> as returned by the operation.</returns>
    T Update(T obj);
    /// <summary>
    /// Gets the total number of items in the collection.
    /// </summary>
    /// <returns>The total count of items.</returns>
    int Count();
    /// <summary>
    /// Returns the number of items that match the specified status.
    /// </summary>
    /// <param name="status">The status value used to filter the items being counted.</param>
    /// <returns>The total count of items matching the specified status.</returns>
    int Count(string status);
    /// <summary>
    /// Retrieves all entities of type <typeparamref name="T"/> and returns them as a list.
    /// </summary>
    /// <returns>A <see cref="List{T}"/> containing all entities of type <typeparamref name="T"/>; an empty list if none are found.</returns>
    List<T> FindAll();
}