import { Injectable } from "@nestjs/common"
import { InjectRepository } from "@nestjs/typeorm"
import { verifyJwtToken } from "src/utils/jwt"
import { Repository } from "typeorm"
import {
  failureResponse,
  successResponse,
} from "../../common/response/response"
import { code } from "../../common/response/response.code"
import { messageKey } from "../../constants/message-keys"
import {
  errorMessage,
  isEmpty,
  successMessage,
  validationMessage,
} from "../../utils/helpers"
import { ProjectActivity } from "../projects/entities/project-activity.entity"
import { CreateActivityTypeDto } from "./dto/create-activity-type.dto"
import { UpdateActivityTypeDto } from "./dto/update-activity-type.dto"
import { ActivityType } from "./entities/activity-type.entity"
import { ActivityTypeRepository } from "./repositories/activity-type.repository"

@Injectable()
export class ActivityTypesService {
  constructor(
    private readonly activityTypeRepository: ActivityTypeRepository,
    @InjectRepository(ProjectActivity)
    private readonly projectActivityEntityRepository: Repository<ProjectActivity>,
  ) {}

  async create(createActivityTypeDto: CreateActivityTypeDto, token: string) {
    const decoded = verifyJwtToken(token)

    if (!decoded) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.invalid_token),
      )
    }

    // Check if activity type with same name exists for the company
    const existingActivityType = await this.activityTypeRepository.getByParams({
      where: {
        company_id: decoded.company_id,
        name: createActivityTypeDto.name,
      },
      findOne: true,
    })

    if (existingActivityType) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.already_exist, {
          ":data": "Activity type",
          ":field": "name",
        }),
      )
    }

    let activityType: any = new ActivityType()

    // Handle is_productive and maximum_threshold_limit logic
    let maximum_threshold_limit = null

    if (createActivityTypeDto.is_productive === 0) {
      maximum_threshold_limit = createActivityTypeDto.maximum_threshold_limit
    }

    activityType = {
      ...createActivityTypeDto,
      status: createActivityTypeDto.status,
      location_required: createActivityTypeDto.location_required,
      is_productive: createActivityTypeDto.is_productive,
      is_business_task: createActivityTypeDto.is_business_task,
      is_personal_task: createActivityTypeDto.is_personal_task,
      is_technical_task: createActivityTypeDto.is_technical_task,
      maximum_threshold_limit: maximum_threshold_limit,
      company_id: decoded.company_id,
      created_by: decoded.user_id,
    }

    await this.activityTypeRepository.save(activityType)

    return successResponse(
      code.SUCCESS,
      successMessage(messageKey.data_add, { ":data": "Activity type" }),
    )
  }

  async findAll(query: any = {}, token: string) {
    try {
      const decoded = verifyJwtToken(token)

      if (!decoded) {
        return failureResponse(
          code.VALIDATION,
          validationMessage(messageKey.invalid_token),
        )
      }

      const {
        page = 1,
        limit = 10,
        search,
        status,
        location_required,
        column_name,
        order = "ASC",
        project_id,
        show_only_assigned_activity,
      } = query

      const skip = (page - 1) * limit
      const take = parseInt(limit.toString())
      const orderDirection = isEmpty(order) ? "ASC" : order.toUpperCase()

      const whereConditions: any = {}
      const searchConditions: any = {}
      let orderBy: any = { name: orderDirection }

      if (!isEmpty(column_name)) {
        switch (column_name) {
          case "name":
            orderBy = { name: orderDirection }
            break
          case "created_at":
            orderBy = { created_at: orderDirection }
            break
        }
      }

      // Add filters
      if (decoded.company_id) {
        whereConditions.company_id = decoded.company_id
      }

      if (status) {
        whereConditions.status = status
      }

      if (location_required !== undefined) {
        whereConditions.location_required = location_required === "true"
      }

      // Add search functionality
      if (search) {
        searchConditions.name = search
        searchConditions.description = search
      }

      let activityTypes: any

      // Handle project-specific filtering
      if (project_id) {
        // Get activity types assigned to the specific project
        const projectActivities =
          await this.projectActivityEntityRepository.find({
            where: { project_id: project_id },
            select: ["activity_type_id"],
          })

        const assignedActivityTypeIds = projectActivities.map(
          (pa) => pa.activity_type_id,
        )

        if (
          show_only_assigned_activity === "true" ||
          show_only_assigned_activity === true
        ) {
          // When show_only_assigned_activity is true, only return assigned activities
          if (assignedActivityTypeIds.length > 0) {
            const params: any = {
              where: whereConditions,
              search: !isEmpty(searchConditions) ? searchConditions : undefined,
              whereNull: ["deleted_at"],
              whereIn: { id: assignedActivityTypeIds },
              relations: ["company:id,name"],
              orderBy,
              take,
              skip,
            }

            activityTypes =
              await this.activityTypeRepository.getByParams(params)
          } else {
            // No assigned activities found, return empty result
            activityTypes = {
              data: [],
              count: 0,
            }
          }
        } else {
          // Original behavior: show assigned activities if exist, otherwise show all
          if (assignedActivityTypeIds.length > 0) {
            // Return only activities assigned to the project
            const params: any = {
              where: whereConditions,
              search: !isEmpty(searchConditions) ? searchConditions : undefined,
              whereNull: ["deleted_at"],
              whereIn: { id: assignedActivityTypeIds },
              relations: ["company:id,name"],
              orderBy,
              take,
              skip,
            }

            activityTypes =
              await this.activityTypeRepository.getByParams(params)
          } else {
            // No activities assigned to project, return all company activities
            activityTypes = await this.activityTypeRepository.getByParams({
              where: whereConditions,
              search: !isEmpty(searchConditions) ? searchConditions : undefined,
              whereNull: ["deleted_at"],
              relations: ["company:id,name"],
              orderBy,
              take,
              skip,
            })
          }
        }
      } else {
        // No project filter, return all activities for the company
        activityTypes = await this.activityTypeRepository.getByParams({
          where: whereConditions,
          search: !isEmpty(searchConditions) ? searchConditions : undefined,
          whereNull: ["deleted_at"],
          relations: ["company:id,name"],
          orderBy,
          take,
          skip,
        })
      }

      return successResponse(
        code.SUCCESS,
        successMessage(messageKey.data_retrieve, { ":data": "Activity types" }),
        activityTypes,
      )
    } catch (error) {
      console.log(error, "error")

      return failureResponse(
        code.VALIDATION,
        errorMessage(messageKey.exception),
      )
    }
  }

  async findOne(id: number) {
    const activityType: any = await this.activityTypeRepository.getByParams({
      where: { id },
      whereNull: ["deleted_at"],
      relations: ["company:id,name"],
      findOne: true,
    })

    if (isEmpty(activityType)) {
      return failureResponse(
        code.VALIDATION,
        errorMessage(messageKey.data_not_found, { ":data": "Activity type" }),
      )
    }

    return successResponse(
      code.SUCCESS,
      successMessage(messageKey.data_retrieve, { ":data": "Activity type" }),
      activityType,
    )
  }

  async update(
    id: number,
    updateActivityTypeDto: UpdateActivityTypeDto,
    token: string,
  ) {
    const decoded = verifyJwtToken(token)

    if (!decoded) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.invalid_token),
      )
    }

    const activityType: any = await this.activityTypeRepository.getByParams({
      where: { id },
      findOne: true,
    })

    if (isEmpty(activityType)) {
      return failureResponse(
        code.VALIDATION,
        errorMessage(messageKey.data_not_found, { ":data": "Activity type" }),
      )
    }

    // Check if activity type with same name exists for the company (excluding current record)
    if (updateActivityTypeDto.name) {
      const existingActivityType =
        await this.activityTypeRepository.getByParams({
          where: {
            company_id: decoded.company_id,
            name: updateActivityTypeDto.name,
          },
          whereNotIn: { id: [id] },
          findOne: true,
        })

      if (existingActivityType) {
        return failureResponse(
          code.VALIDATION,
          validationMessage(messageKey.already_exist, {
            ":data": "Activity type",
            ":field": "name",
          }),
        )
      }
    }

    // Update the activity type
    Object.assign(activityType, updateActivityTypeDto)
    activityType.updated_by = decoded.user_id
    await this.activityTypeRepository.save(activityType)

    return successResponse(
      code.SUCCESS,
      successMessage(messageKey.data_update, { ":data": "Activity type" }),
    )
  }

  async remove(id: number, token: string) {
    const decoded = verifyJwtToken(token)

    if (!decoded) {
      return failureResponse(
        code.VALIDATION,
        validationMessage(messageKey.invalid_token),
      )
    }

    const activityType: any = await this.activityTypeRepository.getByParams({
      where: { id },
      findOne: true,
    })

    if (isEmpty(activityType)) {
      return failureResponse(
        code.VALIDATION,
        errorMessage(messageKey.data_not_found, { ":data": "Activity type" }),
      )
    }

    // Soft delete
    await this.activityTypeRepository.remove({ id: activityType.id })

    await this.activityTypeRepository.save(
      {
        id: activityType.id,
        deleted_by: decoded.user_id,
      },
      { id: activityType.id },
    )

    return successResponse(
      code.SUCCESS,
      successMessage(messageKey.data_removed, { ":data": "Activity type" }),
    )
  }

  async checkActivityTypeExist(name: string, companyId: number) {
    const activityType = await this.activityTypeRepository.getByParams({
      where: {
        name: name,
        company_id: companyId,
      },
      findOne: true,
    })

    return !isEmpty(activityType)
  }
}
