import { Domain, Sender } from "@prisma/client";
import { CreateSenderDTO } from "../dtos/create-sender-dto";
import { UpdateSenderDTO } from "../dtos/update-sender-dto";
import { PublicSender, SendersRepository } from "./senders-repository";

export class InMemorySendersRepository implements SendersRepository {
  public items: Sender[] = [];
  public domains: Domain[] = [];

  private toPublic(sender: Sender): PublicSender {
    const domain = this.domains.find((item) => item.id === sender.domainId) ?? null;
    return {
      id: sender.id,
      name: sender.name,
      fromEmail: sender.fromEmail,
      provider: sender.provider,
      smtpHost: sender.smtpHost,
      smtpPort: sender.smtpPort,
      smtpUser: sender.smtpUser,
      domainId: sender.domainId,
      domain: domain
        ? { id: domain.id, domain: domain.domain, verificationStatus: domain.verificationStatus }
        : null,
    };
  }

  async findById(id: string): Promise<Sender | null> {
    const sender = this.items.find((item) => item.id === id);
    return sender ?? null;
  }

  async findByIdWithDomain(id: string): Promise<(Sender & { domain: Domain | null }) | null> {
    const sender = this.items.find((item) => item.id === id);
    if (!sender) {
      return null;
    }
    const domain = this.domains.find((item) => item.id === sender.domainId) ?? null;
    return { ...sender, domain };
  }

  async findByUserId(userId: string): Promise<PublicSender[]> {
    return this.items.filter((item) => item.userId === userId).map((item) => this.toPublic(item));
  }

  async searchByUserId(userId: string, query: string, limit: number): Promise<PublicSender[]> {
    const normalized = query.toLowerCase();

    return this.items
      .filter(
        (item) =>
          item.userId === userId &&
          (item.name.toLowerCase().includes(normalized) || item.fromEmail.toLowerCase().includes(normalized))
      )
      .slice(0, limit)
      .map((item) => this.toPublic(item));
  }

  async findFirstByUserId(userId: string): Promise<Sender | null> {
    const sender = this.items.find((item) => item.userId === userId);
    return sender ?? null;
  }

  async create(data: CreateSenderDTO & { encryptedPass?: string }): Promise<PublicSender> {
    const sender: Sender = {
      id: `csender${this.items.length + 1}`,
      name: data.name,
      fromEmail: data.fromEmail,
      provider: data.provider,
      smtpHost: data.smtpHost ?? null,
      smtpPort: data.smtpPort ?? null,
      smtpUser: data.smtpUser ?? null,
      smtpPass: data.encryptedPass ?? null,
      domainId: data.domainId ?? null,
      userId: data.userId,
      createdAt: new Date(),
      updatedAt: new Date(),
    };

    this.items.push(sender);

    return this.toPublic(sender);
  }

  async update(
    id: string,
    data: Omit<UpdateSenderDTO, "smtpPass"> & { encryptedPass?: string }
  ): Promise<PublicSender> {
    const sender = this.items.find((item) => item.id === id);
    if (!sender) {
      throw new Error("Sender not found");
    }

    sender.name = data.name;
    sender.fromEmail = data.fromEmail;
    sender.provider = data.provider;
    sender.smtpHost = data.smtpHost ?? null;
    sender.smtpPort = data.smtpPort ?? null;
    sender.smtpUser = data.smtpUser ?? null;
    if (data.encryptedPass !== undefined) {
      sender.smtpPass = data.encryptedPass;
    }
    sender.domainId = data.domainId ?? null;
    sender.updatedAt = new Date();

    return this.toPublic(sender);
  }

  async delete(id: string): Promise<void> {
    const index = this.items.findIndex((item) => item.id === id);
    if (index !== -1) {
      this.items.splice(index, 1);
    }
  }
}
