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

namespace ContactManagementSystem.Services
{
    /// <summary>
    /// Service layer for Contact business logic
    /// Demonstrates: Service Pattern, Dependency Injection
    /// </summary>
    public class ContactService : IDisposable
    {
        private readonly IContactRepository _repository;
        private bool _disposed = false;

        #region Constructor

        /// <summary>
        /// Constructor with dependency injection
        /// </summary>
        public ContactService(IContactRepository repository)
        {
            _repository = repository ?? throw new ArgumentNullException(nameof(repository));
        }

        #endregion

        #region CRUD Operations

        /// <summary>
        /// Gets all contacts
        /// </summary>
        public async Task<List<Contact>> GetAllContactsAsync()
        {
            return await _repository.GetAllAsync();
        }

        /// <summary>
        /// Gets a contact by ID
        /// </summary>
        public async Task<Contact> GetContactByIdAsync(int id)
        {
            if (id <= 0)
                throw new ArgumentException("Contact ID must be greater than 0", nameof(id));

            return await _repository.GetByIdAsync(id);
        }

        /// <summary>
        /// Creates a new contact with validation
        /// </summary>
        public async Task<Contact> CreateContactAsync(Contact contact)
        {
            // Validation
            if (contact == null)
                throw new ArgumentNullException(nameof(contact));

            if (string.IsNullOrWhiteSpace(contact.FirstName))
                throw new ArgumentException("First name is required", nameof(contact.FirstName));

            if (string.IsNullOrWhiteSpace(contact.LastName))
                throw new ArgumentException("Last name is required", nameof(contact.LastName));

            if (string.IsNullOrWhiteSpace(contact.Email))
                throw new ArgumentException("Email is required", nameof(contact.Email));

            if (string.IsNullOrWhiteSpace(contact.PhoneNumber))
                throw new ArgumentException("Phone number is required", nameof(contact.PhoneNumber));

            // Business rule: Check for duplicate email
            if (await _repository.EmailExistsAsync(contact.Email))
                throw new InvalidOperationException($"A contact with email '{contact.Email}' already exists");

            // Create contact
            return await _repository.AddAsync(contact);
        }

        /// <summary>
        /// Updates an existing contact
        /// </summary>
        public async Task<bool> UpdateContactAsync(Contact contact)
        {
            if (contact == null)
                throw new ArgumentNullException(nameof(contact));

            if (contact.Id <= 0)
                throw new ArgumentException("Contact ID must be greater than 0", nameof(contact.Id));

            // Check if contact exists
            var existing = await _repository.GetByIdAsync(contact.Id);
            if (existing == null)
                throw new InvalidOperationException($"Contact with ID {contact.Id} not found");

            return await _repository.UpdateAsync(contact);
        }

        /// <summary>
        /// Deletes a contact
        /// </summary>
        public async Task<bool> DeleteContactAsync(int id)
        {
            if (id <= 0)
                throw new ArgumentException("Contact ID must be greater than 0", nameof(id));

            // Check if contact exists
            var existing = await _repository.GetByIdAsync(id);
            if (existing == null)
                return false;

            return await _repository.DeleteAsync(id);
        }

        #endregion

        #region Query Operations

        /// <summary>
        /// Searches contacts by term
        /// </summary>
        public async Task<List<Contact>> SearchContactsAsync(string searchTerm)
        {
            if (string.IsNullOrWhiteSpace(searchTerm))
                return new List<Contact>();

            return await _repository.SearchAsync(searchTerm);
        }

        /// <summary>
        /// Gets favorite contacts
        /// </summary>
        public async Task<List<Contact>> GetFavoriteContactsAsync()
        {
            return await _repository.GetFavoritesAsync();
        }

        /// <summary>
        /// Gets contacts by company
        /// </summary>
        public async Task<List<Contact>> GetContactsByCompanyAsync(string company)
        {
            if (string.IsNullOrWhiteSpace(company))
                throw new ArgumentException("Company name cannot be empty", nameof(company));

            return await _repository.GetByCompanyAsync(company);
        }

        /// <summary>
        /// Toggles favorite status
        /// </summary>
        public async Task<bool> ToggleFavoriteAsync(int id)
        {
            if (id <= 0)
                throw new ArgumentException("Contact ID must be greater than 0", nameof(id));

            var contact = await _repository.GetByIdAsync(id);
            if (contact == null)
                throw new InvalidOperationException($"Contact with ID {id} not found");

            contact.IsFavorite = !contact.IsFavorite;
            return await _repository.UpdateAsync(contact);
        }

        #endregion

        #region Utility Operations

        /// <summary>
        /// Gets total contact count
        /// </summary>
        public async Task<int> GetContactCountAsync()
        {
            return await _repository.GetCountAsync();
        }

        /// <summary>
        /// Validates contact data
        /// </summary>
        public bool ValidateContact(Contact contact)
        {
            if (contact == null)
                return false;

            if (string.IsNullOrWhiteSpace(contact.FirstName))
                return false;

            if (string.IsNullOrWhiteSpace(contact.LastName))
                return false;

            if (string.IsNullOrWhiteSpace(contact.Email))
                return false;

            if (string.IsNullOrWhiteSpace(contact.PhoneNumber))
                return false;

            return true;
        }

        #endregion

        #region IDisposable

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _repository?.Dispose();
                }
                _disposed = true;
            }
        }

        #endregion
    }
}

/* 
 * 
 * SERVICE LAYER BENEFITS:
 * - Separates business logic from data access
 * - Centralized validation
 * - Reusable business rules
 * - Easier to test (mock repository)
 * - Can coordinate multiple repositories
 * 
 * DEPENDENCY INJECTION:
 * - Service depends on IContactRepository interface
 * - Repository implementation injected via constructor
 * - Enables testing with mock repositories
 * - Loose coupling between layers
 * 
 * VALIDATION STRATEGY:
 * - Input validation in service layer
 * - Business rule enforcement (duplicate email)
 * - Throw exceptions for invalid operations
 * - Repository handles data validation
 * 
 * TESTABILITY:
 * - All methods use injected repository
 * - No direct database access
 * - Easy to mock repository behavior
 * - Can test business logic in isolation
 */
