import { translateLinked, translateShow } from '@api/helpers/translate.helper';
import { DrizzleService } from '@lib/drizzle/src/drizzle.service';
import { Injectable } from '@nestjs/common';
import {
  and,
  asc,
  count,
  desc,
  eq,
  gte,
  inArray,
  like,
  lte,
  sql,
  SQL,
} from 'drizzle-orm';
import { tnBanner } from 'drizzle/schema';
import {
  BannerImageDto,
  CreateBannerDto,
  GetCommonBannerListDto,
  UpdateBannerWithoutImgDto,
} from './banner.dto';

@Injectable()
export class BannerRepository {
  constructor(private drizzle: DrizzleService) {}
  async getDetail(id: number) {
    const [detail] = await this.drizzle
      .select({
        bnnId: tnBanner.bnnId,
        bnnName: tnBanner.bnnName,
        bnnTitle: tnBanner.bnnTitle,
        bnnSort: tnBanner.bnnSort,
        bnnLocationType: sql<string>`GET_STATUS(${tnBanner.bnnLocationType})`,
        bnnShow: translateShow(tnBanner.bnnShow).as('bnnShow'),
        bnnLinked: translateLinked(tnBanner.bnnLinked).as('bnnLinked'),
        bnnLink: tnBanner.bnnLink,
        bnnImg: tnBanner.bnnImg,
        bnnOpenedAt: tnBanner.bnnOpenedAt,
        bnnClosedAt: tnBanner.bnnClosedAt,
        bnnCreatedAt: tnBanner.bnnCreatedAt,
        bnnUpdatedAt: tnBanner.bnnUpdatedAt,
      })
      .from(tnBanner)
      .where(eq(tnBanner.bnnId, id))
      .limit(1);
    return detail;
  }

  async create(banner: CreateBannerDto, image: BannerImageDto) {
    const createData = { ...banner, ...image };
    await this.drizzle.insert(tnBanner).values(createData);
  }

  async update(
    id: number,
    banner: UpdateBannerWithoutImgDto,
    image: BannerImageDto,
  ) {
    const updateData = { ...banner, ...image };
    await this.drizzle
      .update(tnBanner)
      .set(updateData)
      .where(eq(tnBanner.bnnId, id));
  }

  async delete(ids: number[]) {
    await this.drizzle.delete(tnBanner).where(inArray(tnBanner.bnnId, ids));
  }

  async getList(
    where: SQL<unknown> | undefined,
    orderBy: SQL<unknown>,
    page: number,
  ) {
    const limit = 10;
    const offset = (+page - 1) * limit;

    const list = await this.drizzle
      .select({
        bnnId: tnBanner.bnnId,
        bnnName: tnBanner.bnnName,
        bnnTitle: tnBanner.bnnTitle,
        bnnSort: tnBanner.bnnSort,
        bnnLocationType: sql<string>`GET_STATUS(${tnBanner.bnnLocationType})`,
        bnnShow: translateShow(tnBanner.bnnShow).as('bnnShow'),
        bnnLinked: translateLinked(tnBanner.bnnLinked).as('bnnLinked'),
        bnnLink: tnBanner.bnnLink,
        bnnImg: tnBanner.bnnImg,
        bnnOpenedAt: tnBanner.bnnOpenedAt,
        bnnClosedAt: tnBanner.bnnClosedAt,
        bnnCreatedAt: tnBanner.bnnCreatedAt,
        bnnUpdatedAt: tnBanner.bnnUpdatedAt,
      })
      .from(tnBanner)
      .where(where)
      .orderBy(orderBy)
      .limit(limit)
      .offset(offset);

    return list;
  }

  async count(where: SQL<unknown> | undefined) {
    const [totalCount] = await this.drizzle
      .select({ count: count() })
      .from(tnBanner)
      .where(where);

    return totalCount.count ?? 0;
  }

  async orderByClause(dto: GetCommonBannerListDto, isAdmin: boolean) {
    const orderField = this.makeOrderField(dto.sortKey);

    if (isAdmin) {
      switch (dto.sortValue) {
        case 'asc': {
          return asc(orderField);
        }
        default: {
          return desc(orderField);
        }
      }
    }
    return sql`${tnBanner.bnnSort} desc, ${tnBanner.bnnCreatedAt} desc`;
  }

  async whereClause(dto: GetCommonBannerListDto) {
    const {
      searchText,
      searchKey,
      dateType,
      startDate,
      endDate,
      bnnLinked,
      bnnShow,
      bnnLocationType,
    } = dto;
    const where: SQL[] = [];

    if (!!startDate && !!endDate) {
      const dateWhere = this.makeDateWhere(dateType, startDate, endDate);
      where.push(...dateWhere);
    }

    if (!!searchText) {
      const searchKeyWhere = this.makeSearchKeyWhere(searchKey, searchText);
      where.push(searchKeyWhere);
    }

    if (!!bnnLocationType) {
      const bannerType = eq(tnBanner.bnnLocationType, bnnLocationType);
      where.push(bannerType);
    }

    if (bnnShow !== undefined) {
      const isShow = eq(tnBanner.bnnShow, bnnShow);
      where.push(isShow);
    }

    if (bnnLinked !== undefined) {
      const isLinked = eq(tnBanner.bnnLinked, bnnLinked);
      where.push(isLinked);
    }
    return and(...where);
  }

  makeSearchKeyWhere(searchKey: string, searchText: string): SQL {
    const likeText = `%${searchText}%`;
    switch (searchKey) {
      case 'bnnName': {
        return like(tnBanner.bnnName, likeText);
      }
      case 'bnnTitle': {
        return like(tnBanner.bnnTitle, likeText);
      }
      default: {
        return like(tnBanner.bnnName, likeText);
      }
    }
  }

  makeDateWhere(dateType: string, startDate: string, endDate: string): SQL[] {
    const where: SQL[] = [];

    switch (dateType) {
      case 'bnnCreatedAt': {
        where.push(gte(tnBanner.bnnCreatedAt, startDate));
        where.push(lte(tnBanner.bnnCreatedAt, endDate));
        return where;
      }
      case 'bnnOpenedAt': {
        where.push(gte(tnBanner.bnnOpenedAt, startDate));
        where.push(lte(tnBanner.bnnClosedAt, endDate));
        return where;
      }
      default: {
        where.push(gte(tnBanner.bnnCreatedAt, startDate));
        where.push(lte(tnBanner.bnnCreatedAt, endDate));
        return where;
      }
    }
  }

  makeOrderField(sortKey: string) {
    switch (sortKey) {
      case 'bnnName': {
        return tnBanner.bnnName;
      }
      case 'bnnTitle': {
        return tnBanner.bnnTitle;
      }
      case 'bnnSort': {
        return tnBanner.bnnSort;
      }
      case 'bnnCreatedAt': {
        return tnBanner.bnnCreatedAt;
      }
      default: {
        return tnBanner.bnnCreatedAt;
      }
    }
  }
}
