import { Injectable } from "@nestjs/common"
import { DataSource } from "typeorm"
import { CompanySubscriptionHistoryRepository } from "../repositories/company-subscription-history.repository"
import { CompanySubscriptionHistory } from "../entities/company-subscription-history.entity"
import { SubscriptionHistoryFiltersDto } from "../dto/subscription-history-filters.dto"
import { determineSubscriptionStatus } from "../../../utils/subscription-status.util"
import {
  SubscriptionStatus,
  DurationType,
} from "../entities/company-subscription.entity"
import { successResponse, failureResponse } from "src/common/response/response"
import { code } from "src/common/response/response.code"
import { successMessage, errorMessage, isEmpty } from "src/utils/helpers"
import { messageKey } from "src/constants/message-keys"

@Injectable()
export class CompanySubscriptionHistoryService {
  constructor(
    private readonly subscriptionHistoryRepository: CompanySubscriptionHistoryRepository,
    private readonly dataSource: DataSource,
  ) {}

  /**
   * Create a new subscription history record
   */
  async createSubscriptionHistory(
    subscriptionData: {
      company_id: number
      subscription_id: number
      subscription_start_date: Date
      subscription_end_date: Date
      duration: number
      duration_type: DurationType
      subscription_amount: number
    },
    createdBy: number,
    manager?: any,
  ) {
    try {
      const history = new CompanySubscriptionHistory()
      history.company_id = subscriptionData.company_id
      history.subscription_id = subscriptionData.subscription_id
      history.subscription_start_date = subscriptionData.subscription_start_date
      history.subscription_end_date = subscriptionData.subscription_end_date
      history.duration = subscriptionData.duration
      history.duration_type = subscriptionData.duration_type
      history.subscription_amount = subscriptionData.subscription_amount
      history.status = determineSubscriptionStatus(
        subscriptionData.subscription_start_date,
        subscriptionData.subscription_end_date,
      )
      history.created_by = createdBy

      return await this.subscriptionHistoryRepository.save(
        history,
        null,
        manager,
      )
    } catch (error) {
      console.error("Error creating subscription history:", error)
      throw error
    }
  }

  /**
   * Mark existing active histories as expired for a company
   */
  async expireActiveHistories(
    companyId: number,
    updatedBy: number,
    manager?: any,
  ) {
    try {
      const activeHistories: any =
        await this.subscriptionHistoryRepository.getByParams({
          where: {
            company_id: companyId,
            status: SubscriptionStatus.ACTIVE,
          },
        })

      if (activeHistories && activeHistories.length > 0) {
        for (const history of activeHistories) {
          await this.subscriptionHistoryRepository.save(
            {
              id: history.id,
              status: SubscriptionStatus.EXPIRED,
              updated_by: updatedBy,
            },
            null,
            manager,
          )
        }
      }
    } catch (error) {
      console.error("Error expiring active histories:", error)
      throw error
    }
  }

  /**
   * Get subscription histories with filters
   */
  async findAll(filters: SubscriptionHistoryFiltersDto) {
    try {
      const {
        search,
        company_id,
        from_date,
        to_date,
        status,
        page = 1,
        limit = 10,
        column_name,
        order = "DESC",
      } = filters

      const offset = (page - 1) * limit
      const orderDirection = isEmpty(order) ? "DESC" : order.toUpperCase()

      const qb = this.dataSource
        .createQueryBuilder("company_subscription_histories", "csh")
        .leftJoin("companies", "c", "csh.company_id = c.id")
        .select([
          "csh.id",
          "csh.company_id",
          "csh.subscription_id",
          "csh.subscription_start_date",
          "csh.subscription_end_date",
          "csh.duration",
          "csh.duration_type",
          "csh.subscription_amount",
          "csh.status",
          "csh.created_at",
          "csh.updated_at",
          "c.name as company_name",
        ])
        .where("csh.deleted_at IS NULL")

      // Apply search filter
      if (search) {
        qb.andWhere(
          "(c.name ILIKE :search OR csh.duration_type ILIKE :search OR csh.status ILIKE :search)",
          { search: `%${search}%` },
        )
      }

      // Apply filters
      if (company_id) {
        qb.andWhere("csh.company_id = :company_id", { company_id })
      }

      if (from_date) {
        qb.andWhere("csh.subscription_start_date >= :from_date", { from_date })
      }

      if (to_date) {
        qb.andWhere("csh.subscription_end_date <= :to_date", { to_date })
      }

      if (status) {
        // Handle dynamic subscription status filtering based on current date
        const today = new Date()
        today.setHours(0, 0, 0, 0)

        switch (status) {
          case SubscriptionStatus.ACTIVE:
            qb.andWhere(
              "csh.subscription_start_date <= :today AND csh.subscription_end_date >= :today",
              { today },
            )
            break
          case SubscriptionStatus.EXPIRED:
            qb.andWhere("csh.subscription_end_date < :today", { today })
            break
          case SubscriptionStatus.UPCOMING:
            qb.andWhere("csh.subscription_start_date > :today", { today })
            break
          default:
            qb.andWhere("csh.status = :status", { status })
        }
      }

      // Get total count before pagination
      const total = await qb.getCount()

      // Apply dynamic sorting based on column_name
      let orderByField: string = "csh.created_at"

      if (!isEmpty(column_name)) {
        switch (column_name) {
          case "company_name":
            orderByField = "c.name"
            break

          case "subscription_amount":
            orderByField = "csh.subscription_amount"
            break

          case "subscription_start_date":
            orderByField = "csh.subscription_start_date"
            break

          case "subscription_end_date":
            orderByField = "csh.subscription_end_date"
            break

          case "duration":
            orderByField = "csh.duration"
            break

          case "duration_type":
            orderByField = "csh.duration_type"
            break

          case "status":
            orderByField = "csh.status"
            break

          case "subscription_duration":
            orderByField = `
        CASE
          WHEN csh.duration_type = 'Days'
            THEN csh.subscription_start_date + (csh.duration || ' days')::interval
          WHEN csh.duration_type = 'Months'
            THEN csh.subscription_start_date + (csh.duration || ' months')::interval
          WHEN csh.duration_type = 'Years'
            THEN csh.subscription_start_date + (csh.duration || ' years')::interval
        END
      `
            break

          case "created_at":
          default:
            orderByField = "csh.created_at"
            break
        }
      }

      // Apply sorting and pagination
      qb.orderBy(orderByField, orderDirection as "ASC" | "DESC")
        .limit(limit)
        .offset(offset)

      const histories = await qb.getRawMany()

      const formattedHistories = histories.map((row) => ({
        id: row.csh_id,
        company_id: row.csh_company_id,
        company_name: row.company_name,
        subscription_id: row.csh_subscription_id,
        subscription_start_date: row.csh_subscription_start_date,
        subscription_end_date: row.csh_subscription_end_date,
        duration: row.csh_duration,
        duration_type: row.csh_duration_type,
        subscription_amount: Number(row.csh_subscription_amount),
        status: row.csh_status,
        created_at: row.csh_created_at,
        updated_at: row.csh_updated_at,
      }))

      return successResponse(
        code.SUCCESS,
        successMessage(messageKey.data_retrieve, {
          ":data": "Subscription Histories",
        }),
        {
          total,
          page,
          limit,
          data: formattedHistories,
        } as any,
      )
    } catch (error) {
      console.error("Error fetching subscription histories:", error)
      return failureResponse(
        code.VALIDATION,
        errorMessage(messageKey.exception),
      )
    }
  }

  /**
   * Get subscription history by ID
   */
  async findOne(id: number) {
    try {
      const qb = this.dataSource
        .createQueryBuilder("company_subscription_histories", "csh")
        .leftJoin("companies", "c", "csh.company_id = c.id")
        .select([
          "csh.id",
          "csh.company_id",
          "csh.subscription_id",
          "csh.subscription_start_date",
          "csh.subscription_end_date",
          "csh.duration",
          "csh.duration_type",
          "csh.subscription_amount",
          "csh.status",
          "csh.created_at",
          "csh.updated_at",
          "c.name as company_name",
        ])
        .where("csh.id = :id", { id })
        .andWhere("csh.deleted_at IS NULL")

      const history = await qb.getRawOne()

      if (!history) {
        return failureResponse(
          code.VALIDATION,
          errorMessage(messageKey.not_found, {
            ":data": "Subscription History",
          }),
        )
      }

      const formattedHistory: any = {
        id: history.csh_id,
        company_id: history.csh_company_id,
        company_name: history.company_name,
        subscription_id: history.csh_subscription_id,
        subscription_start_date: history.csh_subscription_start_date,
        subscription_end_date: history.csh_subscription_end_date,
        duration: history.csh_duration,
        duration_type: history.csh_duration_type,
        subscription_amount: Number(history.csh_subscription_amount),
        status: history.csh_status,
        created_at: history.csh_created_at,
        updated_at: history.csh_updated_at,
      }

      return successResponse(
        code.SUCCESS,
        successMessage(messageKey.data_retrieve, {
          ":data": "Subscription History",
        }),
        formattedHistory,
      )
    } catch (error) {
      console.error("Error fetching subscription history:", error)
      return failureResponse(
        code.VALIDATION,
        errorMessage(messageKey.exception),
      )
    }
  }
}
