using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ContactManagementSystem.Models;

namespace ContactManagementSystem.Data.Repositories
{
    /// <summary>
    /// Interface defining the contract for Contact repository operations
    /// Demonstrates: Repository Pattern, Dependency Inversion Principle (SOLID)
    /// </summary>
    public interface IContactRepository : IDisposable
    {
        #region Synchronous CRUD Operations

        /// <summary>
        /// Gets all contacts from the database
        /// </summary>
        /// <returns>List of all contacts</returns>
        List<Contact> GetAll();

        /// <summary>
        /// Gets a contact by its ID
        /// </summary>
        /// <param name="id">Contact ID</param>
        /// <returns>Contact if found, null otherwise</returns>
        Contact GetById(int id);

        /// <summary>
        /// Adds a new contact to the database
        /// </summary>
        /// <param name="contact">Contact to add</param>
        /// <returns>The added contact with generated ID</returns>
        Contact Add(Contact contact);

        /// <summary>
        /// Updates an existing contact in the database
        /// </summary>
        /// <param name="contact">Contact with updated information</param>
        /// <returns>True if successful, false otherwise</returns>
        bool Update(Contact contact);

        /// <summary>
        /// Deletes a contact from the database
        /// </summary>
        /// <param name="id">ID of contact to delete</param>
        /// <returns>True if successful, false otherwise</returns>
        bool Delete(int id);

        #endregion

        #region Asynchronous CRUD Operations

        /// <summary>
        /// Gets all contacts from the database asynchronously
        /// </summary>
        /// <returns>Task containing list of all contacts</returns>
        Task<List<Contact>> GetAllAsync();

        /// <summary>
        /// Gets a contact by its ID asynchronously
        /// </summary>
        /// <param name="id">Contact ID</param>
        /// <returns>Task containing contact if found, null otherwise</returns>
        Task<Contact> GetByIdAsync(int id);

        /// <summary>
        /// Adds a new contact to the database asynchronously
        /// </summary>
        /// <param name="contact">Contact to add</param>
        /// <returns>Task containing the added contact with generated ID</returns>
        Task<Contact> AddAsync(Contact contact);

        /// <summary>
        /// Updates an existing contact in the database asynchronously
        /// </summary>
        /// <param name="contact">Contact with updated information</param>
        /// <returns>Task containing true if successful, false otherwise</returns>
        Task<bool> UpdateAsync(Contact contact);

        /// <summary>
        /// Deletes a contact from the database asynchronously
        /// </summary>
        /// <param name="id">ID of contact to delete</param>
        /// <returns>Task containing true if successful, false otherwise</returns>
        Task<bool> DeleteAsync(int id);

        #endregion

        #region Query Operations

        /// <summary>
        /// Searches for contacts matching the search term
        /// </summary>
        /// <param name="searchTerm">Term to search for</param>
        /// <returns>List of matching contacts</returns>
        List<Contact> Search(string searchTerm);

        /// <summary>
        /// Searches for contacts matching the search term asynchronously
        /// </summary>
        /// <param name="searchTerm">Term to search for</param>
        /// <returns>Task containing list of matching contacts</returns>
        Task<List<Contact>> SearchAsync(string searchTerm);

        /// <summary>
        /// Gets contacts by company name
        /// </summary>
        /// <param name="company">Company name</param>
        /// <returns>List of contacts working at the company</returns>
        List<Contact> GetByCompany(string company);

        /// <summary>
        /// Gets contacts by company name asynchronously
        /// </summary>
        /// <param name="company">Company name</param>
        /// <returns>Task containing list of contacts working at the company</returns>
        Task<List<Contact>> GetByCompanyAsync(string company);

        /// <summary>
        /// Gets all favorite contacts
        /// </summary>
        /// <returns>List of favorite contacts</returns>
        List<Contact> GetFavorites();

        /// <summary>
        /// Gets all favorite contacts asynchronously
        /// </summary>
        /// <returns>Task containing list of favorite contacts</returns>
        Task<List<Contact>> GetFavoritesAsync();

        /// <summary>
        /// Gets contacts with pagination
        /// </summary>
        /// <param name="pageNumber">Page number (1-based)</param>
        /// <param name="pageSize">Number of items per page</param>
        /// <returns>List of contacts for the specified page</returns>
        List<Contact> GetPaged(int pageNumber, int pageSize);

        /// <summary>
        /// Gets contacts with pagination asynchronously
        /// </summary>
        /// <param name="pageNumber">Page number (1-based)</param>
        /// <param name="pageSize">Number of items per page</param>
        /// <returns>Task containing list of contacts for the specified page</returns>
        Task<List<Contact>> GetPagedAsync(int pageNumber, int pageSize);

        #endregion

        #region Utility Operations

        /// <summary>
        /// Gets the total count of contacts
        /// </summary>
        /// <returns>Total number of contacts</returns>
        int GetCount();

        /// <summary>
        /// Gets the total count of contacts asynchronously
        /// </summary>
        /// <returns>Task containing total number of contacts</returns>
        Task<int> GetCountAsync();

        /// <summary>
        /// Checks if a contact with the given email exists
        /// </summary>
        /// <param name="email">Email to check</param>
        /// <returns>True if exists, false otherwise</returns>
        bool EmailExists(string email);

        /// <summary>
        /// Checks if a contact with the given email exists asynchronously
        /// </summary>
        /// <param name="email">Email to check</param>
        /// <returns>Task containing true if exists, false otherwise</returns>
        Task<bool> EmailExistsAsync(string email);

        #endregion
    }
}

/* INSTRUCTOR NOTES:
 * 
 * Interface Benefits:
 * - Defines contract without implementation
 * - Enables dependency injection
 * - Makes code testable (can create mock implementations)
 * - Follows Interface Segregation Principle
 * - Allows multiple implementations (e.g., SQL, MongoDB, in-memory)
 * 
 * Why Both Sync and Async?
 * - Console apps can use sync methods
 * - Web applications benefit from async methods
 * - Async is recommended for I/O operations
 * - Provides flexibility for different use cases
 * 
 * Repository Pattern Benefits:
 * - Abstracts data access logic
 * - Centralized data access rules
 * - Easier to test business logic
 * - Can swap data sources without changing business logic
 * - Follows Dependency Inversion Principle (SOLID)
 * 
 * When to Use Repository Pattern:
 * ✅ Large applications with complex data access
 * ✅ When you need testability
 * ✅ When data source might change
 * ✅ Team development with clear separation of concerns
 * 
 * When NOT to Use:
 * ❌ Very small applications
 * ❌ Simple CRUD with no business logic
 * ❌ Rapid prototyping
 * ❌ When it's overkill for the project scope
 */
