import { describe, it, expect, beforeEach, vi } from "vitest";
import { InMemorySendersRepository } from "../repositories/in-memory-senders-repository";
import { InMemoryDomainsRepository } from "@/modules/domains/repositories/in-memory-domains-repository";
import { UpdateSenderUseCase } from "./update-sender-use-case";
import { AppError } from "@/core/errors/app-error";

vi.mock("@/shared/infra/crypto/encryption", () => ({
  encrypt: vi.fn().mockReturnValue("new-encrypted-secret"),
}));

let sendersRepository: InMemorySendersRepository;
let domainsRepository: InMemoryDomainsRepository;
let sut: UpdateSenderUseCase;

describe("Update Sender Use Case", () => {
  beforeEach(() => {
    sendersRepository = new InMemorySendersRepository();
    domainsRepository = new InMemoryDomainsRepository();
    sut = new UpdateSenderUseCase(sendersRepository, domainsRepository);
  });

  it("should update non-sensitive fields", async () => {
    const created = await sendersRepository.create({
      name: "Sender",
      fromEmail: "sender@example.com",
      provider: "SMTP",
      smtpHost: "smtp.com",
      smtpPort: 587,
      smtpUser: "user",
      userId: "user-1",
      encryptedPass: "enc-pass",
    });

    const { sender } = await sut.execute({
      id: created.id,
      userId: "user-1",
      body: {
        name: "New Name",
        fromEmail: "new@example.com",
        provider: "SMTP",
        smtpHost: "smtp.new.com",
        smtpPort: 465,
        smtpUser: "new-user",
      },
    });

    expect(sender.name).toEqual("New Name");
    expect(sender.fromEmail).toEqual("new@example.com");
    expect(sender.smtpHost).toEqual("smtp.new.com");
    expect(sender.smtpPort).toEqual(465);
    expect(sender.smtpUser).toEqual("new-user");
  });

  it("should keep the current password when smtpPass is empty/absent", async () => {
    const created = await sendersRepository.create({
      name: "Sender",
      fromEmail: "sender@example.com",
      provider: "SMTP",
      smtpHost: "smtp.com",
      smtpPort: 587,
      smtpUser: "user",
      userId: "user-1",
      encryptedPass: "enc-pass",
    });

    await sut.execute({
      id: created.id,
      userId: "user-1",
      body: {
        name: "Sender",
        fromEmail: "sender@example.com",
        provider: "SMTP",
        smtpHost: "smtp.com",
        smtpPort: 587,
        smtpUser: "user",
        smtpPass: "",
      },
    });

    const stored = await sendersRepository.findById(created.id);
    expect(stored?.smtpPass).toEqual("enc-pass");
  });

  it("should re-encrypt the password when smtpPass is filled", async () => {
    const created = await sendersRepository.create({
      name: "Sender",
      fromEmail: "sender@example.com",
      provider: "SMTP",
      smtpHost: "smtp.com",
      smtpPort: 587,
      smtpUser: "user",
      userId: "user-1",
      encryptedPass: "enc-pass",
    });

    await sut.execute({
      id: created.id,
      userId: "user-1",
      body: {
        name: "Sender",
        fromEmail: "sender@example.com",
        provider: "SMTP",
        smtpHost: "smtp.com",
        smtpPort: 587,
        smtpUser: "user",
        smtpPass: "new-pass",
      },
    });

    const stored = await sendersRepository.findById(created.id);
    expect(stored?.smtpPass).toEqual("new-encrypted-secret");
  });

  it("should not allow editing another user's sender", async () => {
    const created = await sendersRepository.create({
      name: "Sender",
      fromEmail: "sender@example.com",
      provider: "SMTP",
      smtpHost: "smtp.com",
      smtpPort: 587,
      smtpUser: "user",
      userId: "user-1",
      encryptedPass: "enc-pass",
    });

    await expect(
      sut.execute({
        id: created.id,
        userId: "user-2",
        body: {
          name: "Hacked",
          fromEmail: "hacked@example.com",
          provider: "SMTP",
          smtpHost: "smtp.com",
          smtpPort: 587,
          smtpUser: "user",
        },
      })
    ).rejects.toBeInstanceOf(AppError);
  });

  it("should reject invalid DTO fields", async () => {
    const created = await sendersRepository.create({
      name: "Sender",
      fromEmail: "sender@example.com",
      provider: "SMTP",
      smtpHost: "smtp.com",
      smtpPort: 587,
      smtpUser: "user",
      userId: "user-1",
      encryptedPass: "enc-pass",
    });

    await expect(
      sut.execute({
        id: created.id,
        userId: "user-1",
        body: {
          name: "Sender",
          fromEmail: "not-an-email",
          provider: "SMTP",
          smtpHost: "smtp.com",
          smtpPort: -1,
          smtpUser: "user",
        },
      })
    ).rejects.toThrow();
  });
});
