using Microsoft.EntityFrameworkCore.ChangeTracking; // EntityEntry<T>
using BibliotekaWspolna; // Customer
using System.Collections.Concurrent; // ConcurrentDictionary

namespace Northwind.WebApi.Repozytoria;

public class RepozytoriumCustomer : IRepozytoriumCustomer
{
   // dane klientów umieszczane są w wielowątkowym słowniku,
   // co znacznie poprawia szybkość pracy
   private static ConcurrentDictionary
    <string, Customer>? pamiecPodreczna;

   // Kontekst danych umieszczamy w polu obiektu,
   // ponieważ tutaj używamy własnej pamięci podręcznej.
   private NorthwindContext db;

  public RepozytoriumCustomer(NorthwindContext wstrzykniecyKontekst)
  {
    db = wstrzykniecyKontekst;

      // załaduj dane klientów z bazy danych i umieść je
      // w słowniku, którego kluczem jest ID klienta
      // następnie przekształć słownik w wielowątkowy obiekt
      // ConcurrentDictionary
      if (pamiecPodreczna is null)
    {
      pamiecPodreczna = new ConcurrentDictionary<string, Customer>(
        db.Customers.ToDictionary(c => c.CustomerId));
    }
  }

  public async Task<Customer?> UtworzAsync(Customer k)
  {
    // normalizowanie ID klienta — tylko wielkie litery
    k.CustomerId = k.CustomerId.ToUpper();

    // dodaj do bazy danych używając EF Core
    EntityEntry<Customer> dodane = await db.Customers.AddAsync(k);
    int affected = await db.SaveChangesAsync();
    if (affected == 1)
    {
      if (pamiecPodreczna is null) return k;
       // jeżeli to nowy klient, to dodaj go do pamięci podręcznej,
       // inaczej wywołaj metodę AktualizujPamiecPodreczna
         return pamiecPodreczna.AddOrUpdate(k.CustomerId, k, AktualizujPamiecPodreczna);
    }
    else
    {
      return null;
    }
  }

  public Task<IEnumerable<Customer>> OdczytajWszystkoAsync()
  {
    // pobierz z pamięci podręcznej - tak jest szybciej
    return Task.FromResult(pamiecPodreczna is null
      ? Enumerable.Empty<Customer>() : pamiecPodreczna.Values);
  }

  public Task<Customer?> OdczytajAsync(string id)
  {
    // pobierz z pamięci podręcznej - tak jest szybciej
    id = id.ToUpper();
    if (pamiecPodreczna is null) return null!;
    pamiecPodreczna.TryGetValue(id, out Customer? k);
    return Task.FromResult(k);
  }

  private Customer AktualizujPamiecPodreczna(string id, Customer k)
  {
    Customer? old;
    if (pamiecPodreczna is not null)
    {
      if (pamiecPodreczna.TryGetValue(id, out old))
      {
        if (pamiecPodreczna.TryUpdate(id, k, old))
        {
          return k;
        }
      }
    }
    return null!;
  }

  public async Task<Customer?> AktualizujAsync(string id, Customer k)
  {
    // normalizowanie Id klienta
    id = id.ToUpper();
    k.CustomerId = k.CustomerId.ToUpper();

    // zaktualizuj w bazie danych
    db.Customers.Update(k);
    int zmienione = await db.SaveChangesAsync();
    if (zmienione == 1)
    {
      // zaktualizuj w pamięci podręczniej
      return AktualizujPamiecPodreczna(id, k);
    }
    return null;
  }

  public async Task<bool?> UsunAsync(string id)
  {
    id = id.ToUpper();

    // usuń z bazy danych
    Customer? k = db.Customers.Find(id);
    if (k is null) return null;
    db.Customers.Remove(k);
    int zmienine = await db.SaveChangesAsync();
    if (zmienine == 1)
    {
      if (pamiecPodreczna is null) return null;
      // usuń z pamięci podręcznej
      return pamiecPodreczna.TryRemove(id, out k);
    }
    else
    {
      return null;
    }
  }
}
