namespace TaxBaik.Infrastructure.Repositories;

using Dapper;
using TaxBaik.Domain.Entities;
using TaxBaik.Domain.Interfaces;

public class InquiryRepository(IDbConnectionFactory connectionFactory) : BaseRepository(connectionFactory), IInquiryRepository
{
    public async Task<int> CreateAsync(Inquiry inquiry, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.QueryFirstAsync<int>(
            @"INSERT INTO inquiries (name, phone, email, service_type, message, status, ip_address, created_at)
              VALUES (@Name, @Phone, @Email, @ServiceType, @Message, @Status, @IpAddress, NOW())
              RETURNING id",
            inquiry);
    }

    public async Task<Inquiry?> GetByIdAsync(int id, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.QueryFirstOrDefaultAsync<Inquiry>(
            @"SELECT id, name, phone, email, service_type, message, status, ip_address,
                     client_id, admin_memo, created_at, updated_at
              FROM inquiries WHERE id = @Id",
            new { Id = id });
    }

    public async Task<(IEnumerable<Inquiry> Items, int Total)> GetPagedAsync(
        int page, int pageSize, string? status = null, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        var offset = (page - 1) * pageSize;

        using var reader = await conn.QueryMultipleAsync(
            @"SELECT id, name, phone, email, service_type, message, status, ip_address,
                     client_id, admin_memo, created_at, updated_at
              FROM inquiries
              WHERE @Status::text IS NULL OR status = @Status
              ORDER BY created_at DESC
              LIMIT @PageSize OFFSET @Offset;

              SELECT COUNT(*) FROM inquiries
              WHERE @Status::text IS NULL OR status = @Status;",
            new { Status = status, PageSize = pageSize, Offset = offset });

        var items = (await reader.ReadAsync<Inquiry>()).ToList();
        var total = await reader.ReadFirstAsync<int>();

        return (items, total);
    }

    public async Task<int> CountAsync(CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.ExecuteScalarAsync<int>("SELECT COUNT(*) FROM inquiries");
    }

    public async Task<int> CountThisMonthAsync(CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.ExecuteScalarAsync<int>(
            @"SELECT COUNT(*)
              FROM inquiries
              WHERE created_at >= date_trunc('month', NOW())
                AND created_at < date_trunc('month', NOW()) + INTERVAL '1 month'");
    }

    public async Task<int> CountByStatusAsync(string status, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.ExecuteScalarAsync<int>(
            "SELECT COUNT(*) FROM inquiries WHERE status = @Status",
            new { Status = status });
    }

    public async Task<int> CountByDateRangeAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.ExecuteScalarAsync<int>(
            @"SELECT COUNT(*)
              FROM inquiries
              WHERE created_at >= @StartDate AND created_at <= @EndDate",
            new { StartDate = startDate, EndDate = endDate });
    }

    public async Task<int> CountByStatusAndDateAsync(string status, DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        return await conn.ExecuteScalarAsync<int>(
            @"SELECT COUNT(*)
              FROM inquiries
              WHERE status = @Status
                AND created_at >= @StartDate
                AND created_at <= @EndDate",
            new { Status = status, StartDate = startDate, EndDate = endDate });
    }

    public async Task UpdateStatusAsync(int id, string status, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        await conn.ExecuteAsync(
            "UPDATE inquiries SET status = @Status, updated_at = NOW() WHERE id = @Id",
            new { Id = id, Status = status });
    }

    public async Task UpdateAdminMemoAsync(int id, string? adminMemo, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        await conn.ExecuteAsync(
            "UPDATE inquiries SET admin_memo = @AdminMemo, updated_at = NOW() WHERE id = @Id",
            new { Id = id, AdminMemo = adminMemo });
    }

    public async Task UpdateAsync(Inquiry inquiry, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        await conn.ExecuteAsync(
            @"UPDATE inquiries
              SET name = @Name,
                  phone = @Phone,
                  email = @Email,
                  service_type = @ServiceType,
                  message = @Message,
                  status = @Status,
                  admin_memo = @AdminMemo,
                  updated_at = NOW()
              WHERE id = @Id",
            inquiry);
    }

    public async Task LinkClientAsync(int inquiryId, int clientId, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        await conn.ExecuteAsync(
            "UPDATE inquiries SET client_id = @ClientId, updated_at = NOW() WHERE id = @Id",
            new { Id = inquiryId, ClientId = clientId });
    }

    public async Task DeleteAsync(int id, CancellationToken cancellationToken = default)
    {
        using var conn = Conn();
        await conn.ExecuteAsync("DELETE FROM inquiries WHERE id = @Id", new { Id = id });
    }
}
