using ContactManagementSystem.Data;
using ContactManagementSystem.Data.Repositories;
using ContactManagementSystem.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using static System.Net.Mime.MediaTypeNames;

namespace ContactManagementSystem
{
    /// <summary>
    /// Main program for Contact Management System - Day 1 Version
    /// Demonstrates: Basic console application, Collections, LINQ basics
    /// </summary>
    class Program
    {
        static async Task Main(string[] args)
        {
            // header
            await MyHeader();

            // Test the database connection
            // await TestDatabaseConnection();

            // Demonstrates Repositories using Contacts
            // await DemoRepository();

            // Demo using two tables with Include()
           // await GetAllContactsWithNotes();

            // Advanced Query
            await AdvancedComplexQuery();
            /*
             * LINQ Keywords Demonstrated:
            .Include() - Eager loading with filtering
            .Where() - Multiple filters (chained)
            .OrderByDescending() - Sorting
            .Select() - Projection (custom anonymous type)
            .Max() - Aggregate function
            .Count - Counting related data
             */
        } // Main

        // Using two tables with an Include
        static async Task GetAllContactsWithNotes()
        {
            Console.WriteLine("Get All Contacts with Notes\n");

            using (var context = new ApplicationDbContext())
            {
                // Get all contacts WITH their notes included
                var contacts = await context.Contacts
                    .Include(c => c.Notes)
                    .ToListAsync();
                
                Console.WriteLine($"Found {contacts.Count} contacts\n");

                foreach (var contact in contacts)
                {
                    Console.WriteLine($"{contact.FirstName} {contact.LastName}");
                    Console.WriteLine($"  Notes: {contact.Notes?.Count ?? 0}");

                    if (contact.Notes != null && contact.Notes.Any())
                    {
                        foreach (var note in contact.Notes)
                        {
                            Console.WriteLine($"    - [{note.Category}] {note.Content}");
                        }
                    }
                    Console.WriteLine();
                }
            }
        }

        // Advanced Query
        static async Task AdvancedComplexQuery()
        {
            Console.WriteLine("ADVANCED QUERY: Multi-filter with LINQ operations\n");

            using (var context = new ApplicationDbContext())
            {
                // Complex query: Get favorite contacts from "Tech Corp" who have 
                // at least 2 notes, including only "Project" or "Business" category notes,
                // ordered by most recent note first

                var result = await context.Contacts
                    .Include(c => c.Notes.Where(n =>
                        n.Category == "Project" || n.Category == "Business"))
                    .Where(c => c.IsFavorite == true)                    // Filter: Favorites only
                    .Where(c => c.Company == "Tech Corp")                // Filter: Specific company
                    .Where(c => c.Notes.Count >= 2)                      // Filter: Has 2+ notes
                    .OrderByDescending(c => c.Notes.Max(n => n.DateCreated))  // Sort: Most recent note
                    .Select(c => new                                     // Project: Custom shape
                    {
                        ContactName = c.FirstName + " " + c.LastName,
                        Company = c.Company,
                        Email = c.Email,
                        TotalNotes = c.Notes.Count,
                        RelevantNotes = c.Notes
                            .Where(n => n.Category == "Project" || n.Category == "Business")
                            .OrderByDescending(n => n.DateCreated)
                            .ToList(),
                        MostRecentNoteDate = c.Notes.Max(n => n.DateCreated)
                    })
                    .ToListAsync();

                Console.WriteLine($"Found {result.Count} matching contact(s)\n");
               
                foreach (var contact in result)
                {
                    Console.WriteLine($"Contact: {contact.ContactName}");
                    Console.WriteLine($"Company: {contact.Company}");
                    Console.WriteLine($"Email: {contact.Email}");
                    Console.WriteLine($"Total Notes: {contact.TotalNotes}");
                    Console.WriteLine($"Most Recent Note: {contact.MostRecentNoteDate:yyyy-MM-dd}");
                    Console.WriteLine($"Relevant Notes ({contact.RelevantNotes.Count}):");

                    foreach (var note in contact.RelevantNotes)
                    {
                        Console.WriteLine($"  [{note.Category}] {note.DateCreated:yyyy-MM-dd}");
                        Console.WriteLine($"  {note.Content.Substring(0, Math.Min(60, note.Content.Length))}...");
                    }
                    Console.WriteLine();
                }
            }
        }



        /// <summary>
        ///  Demo for Repositories
        /// </summary>
        /// <returns></returns>
        /// 
        static async Task DemoRepository()
        {
            using (var repository = new ContactRepository())
            {
                try
                {
                    // Test 1: Get all contacts
                    Console.WriteLine("1. Getting all contacts...");
                    var contacts = await repository.GetAllAsync();
                    Console.WriteLine($"   Found {contacts.Count} contacts\n");

                    // Test 2: Get favorites
                    Console.WriteLine("2. Getting favorite contacts...");
                    var favorites = await repository.GetFavoritesAsync();
                    Console.WriteLine($"   Found {favorites.Count} favorites:");
                    foreach (var fav in favorites)
                    {
                        Console.WriteLine($"   - {fav.FirstName} {fav.LastName}");
                    }
                    Console.WriteLine();

                    // Test 3: Search
                    Console.WriteLine("3. Searching for 'Tech'...");
                    var searchResults = await repository.SearchAsync("Tech");
                    Console.WriteLine($"   Found {searchResults.Count} matches:");
                    foreach (var result in searchResults)
                    {
                        Console.WriteLine($"   - {result.FirstName} {result.LastName} - {result.Company}");
                    }
                    Console.WriteLine();

                    // Test 4: Add new contact
                    Console.WriteLine("4. Adding new contact...");
                    var newContact = new Contact
                    {
                        FirstName = "Test",
                        LastName = "User",
                        Email = "test2.user@example.com",
                        PhoneNumber = "5155559999",
                        Company = "Test Corp",
                        IsFavorite = false // 0/1
                    };
                    var added = await repository.AddAsync(newContact);
                    Console.WriteLine($"   Added: {added.FirstName} {added.LastName} (ID: {added.Id})\n");

                    // Test 5: Update contact
                    Console.WriteLine("5. Updating contact...");
                    added.IsFavorite = true;
                    added.Company = "Updated Corp";
                    bool updated = await repository.UpdateAsync(added);
                    Console.WriteLine($"   Updated: {updated}\n");

                    // Test 6: Get by ID
                    Console.WriteLine("6. Getting contact by ID...");
                    var retrieved = await repository.GetByIdAsync(added.Id);
                    Console.WriteLine($"   Retrieved: {retrieved.FirstName} {retrieved.LastName}");
                    Console.WriteLine($"   Company: {retrieved.Company}");
                    Console.WriteLine($"   Favorite: {retrieved.IsFavorite}\n");



                    /*
                    // Test 7: Delete contact
                    Console.WriteLine("7. Deleting test contact...");
                    bool deleted = await repository.DeleteAsync(added.Id);
                    Console.WriteLine($"   Deleted: {deleted}\n");

                    // Test 8: Get count
                    Console.WriteLine("8. Getting total count...");
                    int count = await repository.GetCountAsync();
                    Console.WriteLine($"   Total contacts: {count}\n");
                    */
                    Console.WriteLine("✓ All repository tests completed!");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"\n✗ Error: {ex.Message}");
                }
            }
        }



        static async Task MyHeader()
        {

            try
            {
                Console.WriteLine("===========================================");
                Console.WriteLine("  Contact Management System - Day 3 Test");
                Console.WriteLine("===========================================\n");
            }
            catch (Exception ex)
            {

                Console.WriteLine(ex.ToString());

            }


        } // MyHeader()

        /// <summary>
        /// Tests the database connection and performs simple queries
        /// </summary>
        static async Task TestDatabaseConnection()
        {
            try
            {
                using (var context = new ApplicationDbContext())
                {
                    Console.WriteLine("Testing database connection...");

                    // Test 1: Can we connect?
                    bool canConnect = await context.Database.CanConnectAsync();

                    if (canConnect)
                    {
                        Console.WriteLine("✓ Database connection successful!\n");
                        // throws day 1
                    }
                    else
                    {
                        Console.WriteLine("✗ Cannot connect to database\n");
                        return;
                    }

                    // Test 2: Count total contacts
                    Console.WriteLine("Running queries...\n");

                    int totalContacts = await context.Contacts.CountAsync();
                    Console.WriteLine($"✓ Total contacts in database: {totalContacts}");

                    // Test 3: Get all contacts
                    var contacts = await context.Contacts.ToListAsync();
                    Console.WriteLine($"✓ Retrieved {contacts.Count} contact(s)\n");

                    // Test 4: Display all contacts
                    if (contacts.Any())
                    {
                        Console.WriteLine("Contact List:");
                        Console.WriteLine(new string('-', 80));
                        Console.WriteLine("{0,-5} {1,-15} {2,-15} {3,-30} {4,-10}",
                            "ID", "First Name", "Last Name", "Email", "Favorite");
                        Console.WriteLine(new string('-', 80));

                        foreach (var contact in contacts)
                        {
                            Console.WriteLine("{0,-5} {1,-15} {2,-15} {3,-30} {4,-10}",
                                contact.Id,
                                contact.FirstName,
                                contact.LastName,
                                contact.Email,
                                contact.IsFavorite ? "Yes" : "No");
                        }
                        Console.WriteLine(new string('-', 80));
                    }
                    else
                    {
                        Console.WriteLine("No contacts found in database.");
                    }

                    // Test 5: Get favorite contacts LINQ
                    Console.WriteLine();
                    var favoriteContacts = await context.Contacts
                        .Where(c => c.IsFavorite)
                        .ToListAsync();

                    Console.WriteLine($"✓ Favorite contacts: {favoriteContacts.Count}");

                    if (favoriteContacts.Any())
                    {
                        foreach (var contact in favoriteContacts)
                        {
                            Console.WriteLine($"  - {contact.FirstName} {contact.LastName} ({contact.Company})");
                        }
                    }
                    /*
                    // Test 6: Get contacts by company
                    Console.WriteLine();
                    var techCorpContacts = await context.Contacts
                        .Where(c => c.Company == "Tech Corp")
                        .ToListAsync();

                    Console.WriteLine($"✓ Tech Corp contacts: {techCorpContacts.Count}");

                    if (techCorpContacts.Any())
                    {
                        foreach (var contact in techCorpContacts)
                        {
                            Console.WriteLine($"  - {contact.FirstName} {contact.LastName} - {contact.JobTitle}");
                        }
                    }

                    // Test 7: Get one specific contact
                    Console.WriteLine();
                    var specificContact = await context.Contacts
                        .FirstOrDefaultAsync(c => c.Email == "john.doe@example.com");

                    if (specificContact != null)
                    {
                        Console.WriteLine("✓ Found specific contact:");
                        Console.WriteLine($"  Name: {specificContact.FirstName} {specificContact.LastName}");
                        Console.WriteLine($"  Email: {specificContact.Email}");
                        Console.WriteLine($"  Phone: {specificContact.PhoneNumber}");
                        Console.WriteLine($"  Company: {specificContact.Company}");
                        Console.WriteLine($"  Job Title: {specificContact.JobTitle}");
                    }

                    // End of testing
                    Console.WriteLine("\n✓ All tests completed successfully!");
                    */
                }
            }
            catch (ArgumentException ex) 
            
            { Console.WriteLine(ex.Message); }

            catch (Exception ex)
            {
                Console.WriteLine("\n✗ Error occurred:");
                Console.WriteLine($"  Message: {ex.Message}");

            }
        }
    }
}

