import {
  NOT_FOUND_MEMBER_ID
} from '@api/constants/api.constant';
import { DrizzleService } from '@lib/drizzle/src';
import {
  Injectable,
  Logger,
  NotFoundException
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { eq } from 'drizzle-orm';
import { tnMember } from 'drizzle/schema';
import { FcmService } from '../fcm/fcm.service';
import { resolveAlarmDeepLink } from './alarm-deeplink.util';
import { AlarmCheckDto, AlarmCreatedDto, AlarmListDto } from './alarm.dto';
import { AlarmRepository } from './alarm.repository';

@Injectable()
export class AlarmService {
  private readonly logger = new Logger(AlarmService.name);

  constructor(
    private alarmRepository: AlarmRepository,
    private drizzle: DrizzleService,
    private fcmService: FcmService,
    private configService: ConfigService,
  ) {}

  async getAlarmList(dto: AlarmListDto) {
    if (!dto.memId) throw new NotFoundException(NOT_FOUND_MEMBER_ID);

    const where = await this.alarmRepository.whereClause(dto);
    const orderBy = await this.alarmRepository.userOrderByClause();
    const list = await this.alarmRepository.getList(where, orderBy, dto.page);
    const count = await this.alarmRepository.count(where);
    const noCheckCount = await this.alarmRepository.noCheckCount(dto.memId!);

    return { noCheckCount, count, list };
  }

  async addAlarm(dto: AlarmCreatedDto) {
    const almIds = await this.alarmRepository.create(dto);

    //* 알람 저장시 FCM_TOKEN를 통한 firebase 앱 푸시 처리도 진행
    try {
      await this.fcmPush(dto, String(almIds[0].almId));
    } catch (e) {
      this.logger.error('FCM 푸시 발송 실패', e);
    }

    return;
  }

  //* 토큰 회원의 알림인지 — 읽음 · 삭제 컨트롤러가 선조회로 쓴다(알림 관리자 경로는 부르지 않는다).
  async isOwned(almId: number, memId: number) {
    //* mut:k11-isowned begin
    return await this.alarmRepository.owned(almId, memId);
    //* mut:k11-isowned end
  }

  async updateAlarmChecked(dto: AlarmCheckDto) {
    return await this.alarmRepository.check(dto);
  }

  async deleteAlarm(dto: AlarmCheckDto) {
    return await this.alarmRepository.delete(dto);
  }

  //* 앱푸시(FCM_TOKEN)
  private async fcmPush(dto: AlarmCreatedDto, almId: string) {
    //* 알람 저장시 FCM 토큰도 발송되도록 조치
    //* 멤버 테이블에서 FCM 토큰 + 푸시 알림 설정 조회
    const [fc] = await this.drizzle
      .select({
        memFcmToken: tnMember.memFcmToken,
        memPushPayment: tnMember.memPushPayment,
        memPushAnalysis: tnMember.memPushAnalysis,
      })
      .from(tnMember)
      .where(eq(tnMember.memId, dto.memId));

    //* 알림 타입별 동의 여부 확인
    //* SND001: 결제(카드사용), SND002: 분석, SND003: 팩스(결제와 동일)
    const isPushAllowed =
      (dto.almType === 'SND001' && fc.memPushPayment === 1) ||  // 결제
      (dto.almType === 'SND002' && fc.memPushAnalysis === 1) || // 분석
      (dto.almType === 'SND003' && fc.memPushPayment === 1);    // 팩스 (결제와 동일)

    //* FC 정보에 FCM_TOKEN이 있고 + 해당 알림 유형에 동의한 경우만 앱 푸시 발송
    if (fc.memFcmToken && isPushAllowed) {
      const baseUrl = await this.configService.get('user.baseUrl');

      //* 알람 타입별 인앱 목적지 (정본: alarm-deeplink.util)
      const deepLink = resolveAlarmDeepLink(dto.almType, dto.almMessage);

      const message =
        dto.almType === 'SND001'
          ? dto.almMessage
          : dto.almType === 'SND003'
            ? dto.almMessage
            : `${dto.almUserName}님의 ${dto.almMessage}`;

      //* firebase에 데이터 전송

      await this.fcmService.sendPush({
        title: '[보험유니버스]',
        body: message,
        token: fc.memFcmToken ?? '',
        redirectUri: baseUrl + deepLink,
        almId: almId,
        deepLink,
      });
    }
  }
}
