import { BaseRepository } from "@edr/api-common";
import { SupportAuthorRole } from "@edr/types";
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";

import { SupportConversation } from "./entities/support-conversation.entity";

export interface ListConversationsOptions {
  search?: string;
  /** Keep only threads with at least one message the side hasn't read. */
  unreadOnly?: boolean;
  page?: number;
  limit?: number;
}

@Injectable()
export class SupportConversationRepository extends BaseRepository<SupportConversation> {
  constructor(
    @InjectRepository(SupportConversation)
    repo: Repository<SupportConversation>,
  ) {
    super(repo);
  }

  /** The company's thread, or null if neither side has spoken yet. */
  async findByCompanyId(companyId: string): Promise<SupportConversation | null> {
    return this.repository.findOne({ where: { companyId } });
  }

  /** Every thread (backoffice shared inbox), most-recently-active first. */
  async listAll(
    side: SupportAuthorRole,
    opts: ListConversationsOptions = {},
  ): Promise<[SupportConversation[], number]> {
    const page = opts.page && opts.page > 0 ? opts.page : 1;
    const limit = opts.limit && opts.limit > 0 ? opts.limit : 20;
    const qb = this.repository
      .createQueryBuilder("c")
      .orderBy("c.last_message_at", "DESC", "NULLS LAST")
      .addOrderBy("c.created_at", "DESC")
      .skip((page - 1) * limit)
      .take(limit);

    if (opts.search?.trim()) {
      qb.andWhere("c.company_name ILIKE :term", {
        term: `%${opts.search.trim()}%`,
      });
    }
    if (opts.unreadOnly) {
      // Same rule as SupportMessageRepository.baseUnreadQuery: a message from
      // the other role, newer than this side's cursor. `cursorCol` is chosen
      // from a closed set below — never caller input.
      const otherRole =
        side === SupportAuthorRole.CUSTOMER
          ? SupportAuthorRole.AGENT
          : SupportAuthorRole.CUSTOMER;
      const cursorCol =
        side === SupportAuthorRole.CUSTOMER
          ? "c.customer_last_read_at"
          : "c.agent_last_read_at";
      qb.andWhere(
        `EXISTS (
           SELECT 1 FROM freight.support_messages m
           WHERE m.conversation_id = c.id
             AND m.deleted_at IS NULL
             AND m.author_role = :otherRole
             AND (${cursorCol} IS NULL OR m.created_at > ${cursorCol})
         )`,
        { otherRole },
      );
    }
    return qb.getManyAndCount();
  }
}
