using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Ikar.Server.Data;
using Ikar.Server.Data.Entities;
using Ikar.Shared;

namespace Ikar.Server.Infrastructure;

public sealed class DatabaseSeeder(IkarDbContext dbContext)
{
    private readonly PasswordHasher<User> _passwordHasher = new();

    public async Task SeedAsync()
    {
        if (await dbContext.Users.AnyAsync())
        {
            return;
        }

        var alice = CreateUser("alice", "Alice Carter", "demo123", "+10000000001");
        var bob = CreateUser("bob", "Bob Miller", "demo123", "+10000000002");
        var carol = CreateUser("carol", "Carol Stone", "demo123", "+10000000003");

        var directChat = new Chat
        {
            Type = ChatType.Direct,
            CreatedBy = alice,
            CreatedAt = DateTimeOffset.UtcNow.AddMinutes(-30),
            LastActivityAt = DateTimeOffset.UtcNow.AddMinutes(-5),
            Members =
            [
                new ChatMember { User = alice, IsOwner = true, JoinedAt = DateTimeOffset.UtcNow.AddMinutes(-30) },
                new ChatMember { User = bob, IsOwner = false, JoinedAt = DateTimeOffset.UtcNow.AddMinutes(-30) }
            ]
        };

        var groupChat = new Chat
        {
            Type = ChatType.Group,
            Title = "Ikar Crew",
            CreatedBy = alice,
            CreatedAt = DateTimeOffset.UtcNow.AddMinutes(-20),
            LastActivityAt = DateTimeOffset.UtcNow.AddMinutes(-2),
            Members =
            [
                new ChatMember { User = alice, IsOwner = true, JoinedAt = DateTimeOffset.UtcNow.AddMinutes(-20) },
                new ChatMember { User = bob, IsOwner = false, JoinedAt = DateTimeOffset.UtcNow.AddMinutes(-20) },
                new ChatMember { User = carol, IsOwner = false, JoinedAt = DateTimeOffset.UtcNow.AddMinutes(-20) }
            ]
        };

        directChat.Messages.Add(new Message
        {
            Chat = directChat,
            Sender = alice,
            Text = "Welcome to Ikar. This is a seeded private dialog.",
            SentAt = DateTimeOffset.UtcNow.AddMinutes(-10)
        });

        directChat.Messages.Add(new Message
        {
            Chat = directChat,
            Sender = bob,
            Text = "Messages are stored in SQLite and delivered through SignalR.",
            SentAt = DateTimeOffset.UtcNow.AddMinutes(-5)
        });

        groupChat.Messages.Add(new Message
        {
            Chat = groupChat,
            Sender = carol,
            Text = "Use this group to validate shared conversations.",
            SentAt = DateTimeOffset.UtcNow.AddMinutes(-2)
        });

        var channel = new Chat
        {
            Type = ChatType.Channel,
            Title = "Ikar Updates",
            CreatedBy = alice,
            CreatedAt = DateTimeOffset.UtcNow.AddMinutes(-15),
            LastActivityAt = DateTimeOffset.UtcNow.AddMinutes(-1),
            Members =
            [
                new ChatMember { User = alice, IsOwner = true, Role = ChatMemberRole.Owner, CanPinMessages = true, CanDeleteMessages = true, CanInviteUsers = true, CanPostMessages = true, JoinedAt = DateTimeOffset.UtcNow.AddMinutes(-15) },
                new ChatMember { User = bob, IsOwner = false, CanPostMessages = false, JoinedAt = DateTimeOffset.UtcNow.AddMinutes(-15) },
                new ChatMember { User = carol, IsOwner = false, CanPostMessages = false, JoinedAt = DateTimeOffset.UtcNow.AddMinutes(-15) }
            ]
        };

        channel.Messages.Add(new Message
        {
            Chat = channel,
            Sender = alice,
            Text = "This channel is broadcast-only. Owners can post, subscribers can read.",
            PostedAsChannel = true,
            SentAt = DateTimeOffset.UtcNow.AddMinutes(-1)
        });

        dbContext.Users.AddRange(alice, bob, carol);
        dbContext.Chats.AddRange(directChat, groupChat, channel);
        await dbContext.SaveChangesAsync();
    }

    private User CreateUser(string username, string displayName, string password, string phoneNumber)
    {
        var user = new User
        {
            Username = username,
            NormalizedUsername = username.ToUpperInvariant(),
            DisplayName = displayName,
            PhoneNumber = phoneNumber,
            NormalizedPhoneNumber = PhoneNumberNormalizer.Normalize(phoneNumber)
        };

        user.PasswordHash = _passwordHasher.HashPassword(user, password);
        return user;
    }
}
