import {
  Body,
  Controller,
  HttpCode,
  HttpStatus,
  Logger,
  NotFoundException,
  Param,
  Post,
} from '@nestjs/common';
import { ApiExcludeController } from '@nestjs/swagger';
import { createHash } from 'crypto';
import { RequireRole } from '../auth/decorators/auth.decorators';
import { ApiKeyRole } from '../auth/entities/api-key.entity';
import { MessageService } from '../message/message.service';
import { UltramsgChatSendDto } from './dto/ultramsg-chat-send.dto';
import { engineQuotedId, toChatId } from './ultramsg-payload';

@ApiExcludeController()
@Controller('ultramsg/:sessionId/messages')
export class UltramsgSendController {
  private readonly logger = new Logger(UltramsgSendController.name);

  constructor(private readonly messages: MessageService) {}

  /**
   * UltraMsg-shaped send used by list/webhook_instant.php (form: token, to, body, msgId).
   * Full path: POST /api/ultramsg/:sessionId/messages/chat
   *
   * Returns a numeric `id` (UltraMsg style). list/webhook_instant.php does `if ($sendid > 0)`
   * and stores into INT `wh_sendid` — a string WA id is treated as failure and triggers a
   * fallback second/third send. Keep PHP untouched by matching UltraMsg's numeric id here.
   */
  @Post('chat')
  @RequireRole(ApiKeyRole.OPERATOR)
  @HttpCode(HttpStatus.OK)
  async sendChat(
    @Param('sessionId') sessionId: string,
    @Body() dto: UltramsgChatSendDto,
  ): Promise<{ id: number }> {
    const chatId = toChatId(dto.to);
    const quotedMessageId = engineQuotedId(dto.msgId);
    const messageId = await this.sendOnce(sessionId, chatId, dto.body, quotedMessageId);
    return { id: numericUltramsgSendId(messageId) };
  }

  private async sendOnce(
    sessionId: string,
    chatId: string,
    text: string,
    quotedMessageId: string | undefined,
  ): Promise<string> {
    try {
      const result = await this.messages.sendText(sessionId, {
        chatId,
        text,
        ...(quotedMessageId ? { quotedMessageId } : {}),
      });
      return result.messageId;
    } catch (error) {
      if (!quotedMessageId || !this.isQuoteLookupMiss(error)) {
        throw error;
      }
      this.logger.warn(
        `Quoted msgId not found; sending without quote (session=${sessionId} chatId=${chatId})`,
      );
      const result = await this.messages.sendText(sessionId, { chatId, text });
      return result.messageId;
    }
  }

  private isQuoteLookupMiss(error: unknown): boolean {
    if (error instanceof NotFoundException) return true;
    const status =
      (error as { status?: number; getStatus?: () => number } | null)?.status ??
      (typeof (error as { getStatus?: () => number })?.getStatus === 'function'
        ? (error as { getStatus: () => number }).getStatus()
        : undefined);
    if (status === 404) return true;
    const message = error instanceof Error ? error.message : String(error ?? '');
    return /not found/i.test(message);
  }
}

/** Stable positive INT for MySQL `wh_sendid` / PHP `$sendid > 0` (never 0). */
export function numericUltramsgSendId(messageId: string): number {
  const hex = createHash('sha1').update(messageId).digest('hex').slice(0, 8);
  const n = Number.parseInt(hex, 16) % 2147483646;
  return n > 0 ? n : 1;
}
