/*
 * File: /src/server/ShadowedRealms.Core/Interfaces/Repositories/IRepository.cs
 * Created: 2025-10-19
 * Last Modified: 2025-10-19
 * Description: Base repository interface defining common CRUD operations with kingdom-scoped data access patterns.
 *              All specific repository interfaces inherit from this to ensure consistent data access patterns
 *              and kingdom boundary enforcement across the entire application.
 * Last Edit Notes: Initial implementation with comprehensive async operations, kingdom scoping, and error handling contracts.
 */

using System.Linq.Expressions;

namespace ShadowedRealms.Core.Interfaces.Repositories
{
    /// <summary>
    /// Base repository interface providing common CRUD operations with kingdom-scoped data access.
    /// All entity repositories must inherit from this interface to ensure consistent data access patterns
    /// and automatic kingdom boundary enforcement.
    /// </summary>
    /// <typeparam name="TEntity">The entity type that this repository manages</typeparam>
    /// <typeparam name="TKey">The primary key type for the entity</typeparam>
    public interface IRepository<TEntity, TKey> where TEntity : class
    {
        #region Kingdom-Scoped Query Operations

        /// <summary>
        /// Gets an entity by its primary key within the specified kingdom context.
        /// Automatically applies kingdom-scoped filtering to prevent cross-kingdom data access.
        /// </summary>
        /// <param name="id">The primary key of the entity to retrieve</param>
        /// <param name="kingdomId">The kingdom context for the query</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>The entity if found within the kingdom, null otherwise</returns>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<TEntity?> GetByIdAsync(TKey id, int kingdomId, CancellationToken cancellationToken = default);

        /// <summary>
        /// Gets an entity by its primary key with related entities included, within the specified kingdom context.
        /// Automatically applies kingdom-scoped filtering to all included navigation properties.
        /// </summary>
        /// <param name="id">The primary key of the entity to retrieve</param>
        /// <param name="kingdomId">The kingdom context for the query</param>
        /// <param name="includeProperties">Navigation properties to include in the query</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>The entity with included properties if found within the kingdom, null otherwise</returns>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid or includeProperties contains invalid property names</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<TEntity?> GetByIdWithIncludesAsync(TKey id, int kingdomId, CancellationToken cancellationToken = default,
            params Expression<Func<TEntity, object>>[] includeProperties);

        /// <summary>
        /// Gets all entities within the specified kingdom context.
        /// Results are automatically filtered to prevent cross-kingdom data access.
        /// </summary>
        /// <param name="kingdomId">The kingdom context for the query</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>All entities belonging to the specified kingdom</returns>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<IEnumerable<TEntity>> GetAllAsync(int kingdomId, CancellationToken cancellationToken = default);

        /// <summary>
        /// Gets entities matching the specified predicate within the kingdom context.
        /// The predicate is combined with kingdom-scoped filtering automatically.
        /// </summary>
        /// <param name="predicate">The condition to filter entities</param>
        /// <param name="kingdomId">The kingdom context for the query</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>Entities matching the predicate within the specified kingdom</returns>
        /// <exception cref="ArgumentNullException">Thrown when predicate is null</exception>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<IEnumerable<TEntity>> GetWhereAsync(Expression<Func<TEntity, bool>> predicate, int kingdomId,
            CancellationToken cancellationToken = default);

        /// <summary>
        /// Gets entities matching the specified predicate with related entities included, within the kingdom context.
        /// Both the predicate and includes are automatically kingdom-scoped.
        /// </summary>
        /// <param name="predicate">The condition to filter entities</param>
        /// <param name="kingdomId">The kingdom context for the query</param>
        /// <param name="includeProperties">Navigation properties to include in the query</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>Entities matching the predicate with included properties within the specified kingdom</returns>
        /// <exception cref="ArgumentNullException">Thrown when predicate is null</exception>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid or includeProperties contains invalid property names</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<IEnumerable<TEntity>> GetWhereWithIncludesAsync(Expression<Func<TEntity, bool>> predicate, int kingdomId,
            CancellationToken cancellationToken = default, params Expression<Func<TEntity, object>>[] includeProperties);

        /// <summary>
        /// Gets the first entity matching the specified predicate within the kingdom context, or null if not found.
        /// Automatically applies kingdom-scoped filtering.
        /// </summary>
        /// <param name="predicate">The condition to filter entities</param>
        /// <param name="kingdomId">The kingdom context for the query</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>The first matching entity within the kingdom, or null if not found</returns>
        /// <exception cref="ArgumentNullException">Thrown when predicate is null</exception>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<TEntity?> GetFirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate, int kingdomId,
            CancellationToken cancellationToken = default);

        #endregion

        #region Paginated Query Operations

        /// <summary>
        /// Gets a paginated list of entities within the specified kingdom context.
        /// Results are automatically kingdom-scoped and ordered for consistent pagination.
        /// </summary>
        /// <param name="pageNumber">The page number (1-based)</param>
        /// <param name="pageSize">The number of entities per page</param>
        /// <param name="kingdomId">The kingdom context for the query</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>Paginated results within the specified kingdom</returns>
        /// <exception cref="ArgumentException">Thrown when pageNumber or pageSize is invalid, or kingdomId is invalid</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<(IEnumerable<TEntity> Items, int TotalCount, int PageCount)> GetPagedAsync(int pageNumber, int pageSize,
            int kingdomId, CancellationToken cancellationToken = default);

        /// <summary>
        /// Gets a paginated list of entities matching the specified predicate within the kingdom context.
        /// Results are automatically kingdom-scoped and ordered for consistent pagination.
        /// </summary>
        /// <param name="predicate">The condition to filter entities</param>
        /// <param name="pageNumber">The page number (1-based)</param>
        /// <param name="pageSize">The number of entities per page</param>
        /// <param name="kingdomId">The kingdom context for the query</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>Paginated filtered results within the specified kingdom</returns>
        /// <exception cref="ArgumentNullException">Thrown when predicate is null</exception>
        /// <exception cref="ArgumentException">Thrown when pageNumber or pageSize is invalid, or kingdomId is invalid</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<(IEnumerable<TEntity> Items, int TotalCount, int PageCount)> GetPagedWhereAsync(
            Expression<Func<TEntity, bool>> predicate, int pageNumber, int pageSize, int kingdomId,
            CancellationToken cancellationToken = default);

        #endregion

        #region Count and Existence Operations

        /// <summary>
        /// Gets the count of all entities within the specified kingdom context.
        /// Automatically applies kingdom-scoped filtering.
        /// </summary>
        /// <param name="kingdomId">The kingdom context for the query</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>The count of entities within the specified kingdom</returns>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<int> CountAsync(int kingdomId, CancellationToken cancellationToken = default);

        /// <summary>
        /// Gets the count of entities matching the specified predicate within the kingdom context.
        /// The predicate is combined with kingdom-scoped filtering automatically.
        /// </summary>
        /// <param name="predicate">The condition to filter entities</param>
        /// <param name="kingdomId">The kingdom context for the query</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>The count of matching entities within the specified kingdom</returns>
        /// <exception cref="ArgumentNullException">Thrown when predicate is null</exception>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<int> CountWhereAsync(Expression<Func<TEntity, bool>> predicate, int kingdomId,
            CancellationToken cancellationToken = default);

        /// <summary>
        /// Checks if any entity exists within the specified kingdom context.
        /// Automatically applies kingdom-scoped filtering.
        /// </summary>
        /// <param name="kingdomId">The kingdom context for the query</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>True if any entities exist within the kingdom, false otherwise</returns>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<bool> AnyAsync(int kingdomId, CancellationToken cancellationToken = default);

        /// <summary>
        /// Checks if any entity matching the specified predicate exists within the kingdom context.
        /// The predicate is combined with kingdom-scoped filtering automatically.
        /// </summary>
        /// <param name="predicate">The condition to filter entities</param>
        /// <param name="kingdomId">The kingdom context for the query</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>True if any matching entities exist within the kingdom, false otherwise</returns>
        /// <exception cref="ArgumentNullException">Thrown when predicate is null</exception>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<bool> AnyAsync(Expression<Func<TEntity, bool>> predicate, int kingdomId,
            CancellationToken cancellationToken = default);

        #endregion

        #region Modification Operations

        /// <summary>
        /// Adds a new entity to the repository within the specified kingdom context.
        /// The entity's kingdom association is automatically validated and enforced.
        /// </summary>
        /// <param name="entity">The entity to add</param>
        /// <param name="kingdomId">The kingdom context for the operation</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>The added entity with any generated values populated</returns>
        /// <exception cref="ArgumentNullException">Thrown when entity is null</exception>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid or entity belongs to different kingdom</exception>
        /// <exception cref="InvalidOperationException">Thrown when entity violates business rules</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<TEntity> AddAsync(TEntity entity, int kingdomId, CancellationToken cancellationToken = default);

        /// <summary>
        /// Adds multiple entities to the repository within the specified kingdom context.
        /// All entities' kingdom associations are automatically validated and enforced.
        /// </summary>
        /// <param name="entities">The entities to add</param>
        /// <param name="kingdomId">The kingdom context for the operation</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>The added entities with any generated values populated</returns>
        /// <exception cref="ArgumentNullException">Thrown when entities collection is null</exception>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid or any entity belongs to different kingdom</exception>
        /// <exception cref="InvalidOperationException">Thrown when any entity violates business rules</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<IEnumerable<TEntity>> AddRangeAsync(IEnumerable<TEntity> entities, int kingdomId,
            CancellationToken cancellationToken = default);

        /// <summary>
        /// Updates an existing entity within the specified kingdom context.
        /// The entity's kingdom association is validated to prevent cross-kingdom modifications.
        /// </summary>
        /// <param name="entity">The entity to update</param>
        /// <param name="kingdomId">The kingdom context for the operation</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>The updated entity</returns>
        /// <exception cref="ArgumentNullException">Thrown when entity is null</exception>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid or entity belongs to different kingdom</exception>
        /// <exception cref="InvalidOperationException">Thrown when entity doesn't exist or violates business rules</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<TEntity> UpdateAsync(TEntity entity, int kingdomId, CancellationToken cancellationToken = default);

        /// <summary>
        /// Updates multiple entities within the specified kingdom context.
        /// All entities' kingdom associations are validated to prevent cross-kingdom modifications.
        /// </summary>
        /// <param name="entities">The entities to update</param>
        /// <param name="kingdomId">The kingdom context for the operation</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>The updated entities</returns>
        /// <exception cref="ArgumentNullException">Thrown when entities collection is null</exception>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid or any entity belongs to different kingdom</exception>
        /// <exception cref="InvalidOperationException">Thrown when any entity doesn't exist or violates business rules</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<IEnumerable<TEntity>> UpdateRangeAsync(IEnumerable<TEntity> entities, int kingdomId,
            CancellationToken cancellationToken = default);

        /// <summary>
        /// Deletes an entity by its primary key within the specified kingdom context.
        /// Automatically validates kingdom association before deletion.
        /// </summary>
        /// <param name="id">The primary key of the entity to delete</param>
        /// <param name="kingdomId">The kingdom context for the operation</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>True if the entity was deleted, false if not found</returns>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid</exception>
        /// <exception cref="InvalidOperationException">Thrown when entity cannot be deleted due to business rules</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<bool> DeleteAsync(TKey id, int kingdomId, CancellationToken cancellationToken = default);

        /// <summary>
        /// Deletes an entity within the specified kingdom context.
        /// Automatically validates kingdom association before deletion.
        /// </summary>
        /// <param name="entity">The entity to delete</param>
        /// <param name="kingdomId">The kingdom context for the operation</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>True if the entity was deleted, false if not found</returns>
        /// <exception cref="ArgumentNullException">Thrown when entity is null</exception>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid or entity belongs to different kingdom</exception>
        /// <exception cref="InvalidOperationException">Thrown when entity cannot be deleted due to business rules</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<bool> DeleteAsync(TEntity entity, int kingdomId, CancellationToken cancellationToken = default);

        /// <summary>
        /// Deletes entities matching the specified predicate within the kingdom context.
        /// The predicate is combined with kingdom-scoped filtering automatically.
        /// </summary>
        /// <param name="predicate">The condition to filter entities for deletion</param>
        /// <param name="kingdomId">The kingdom context for the operation</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>The number of entities deleted</returns>
        /// <exception cref="ArgumentNullException">Thrown when predicate is null</exception>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid</exception>
        /// <exception cref="InvalidOperationException">Thrown when entities cannot be deleted due to business rules</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<int> DeleteWhereAsync(Expression<Func<TEntity, bool>> predicate, int kingdomId,
            CancellationToken cancellationToken = default);

        #endregion

        #region Transaction and Performance Operations

        /// <summary>
        /// Executes a database operation within a transaction scope, automatically handling rollback on exceptions.
        /// All operations within the transaction maintain kingdom-scoped security.
        /// </summary>
        /// <typeparam name="TResult">The return type of the operation</typeparam>
        /// <param name="operation">The operation to execute within the transaction</param>
        /// <param name="kingdomId">The kingdom context for the transaction</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>The result of the operation</returns>
        /// <exception cref="ArgumentNullException">Thrown when operation is null</exception>
        /// <exception cref="ArgumentException">Thrown when kingdomId is invalid</exception>
        /// <exception cref="InvalidOperationException">Thrown when transaction fails</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<TResult> ExecuteInTransactionAsync<TResult>(Func<Task<TResult>> operation, int kingdomId,
            CancellationToken cancellationToken = default);

        /// <summary>
        /// Executes a raw SQL query with parameters, automatically applying kingdom-scoped filtering.
        /// Use only when LINQ queries are insufficient for performance or complexity requirements.
        /// </summary>
        /// <param name="sql">The SQL query with parameter placeholders</param>
        /// <param name="kingdomId">The kingdom context for the query</param>
        /// <param name="parameters">The parameters for the SQL query</param>
        /// <param name="cancellationToken">Cancellation token for async operation</param>
        /// <returns>Entities returned by the SQL query within the kingdom context</returns>
        /// <exception cref="ArgumentException">Thrown when sql is null/empty or kingdomId is invalid</exception>
        /// <exception cref="InvalidOperationException">Thrown when SQL execution fails</exception>
        /// <exception cref="OperationCanceledException">Thrown when operation is cancelled</exception>
        Task<IEnumerable<TEntity>> ExecuteRawSqlAsync(string sql, int kingdomId,
            CancellationToken cancellationToken = default, params object[] parameters);

        #endregion
    }
}