import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { UpdateSettingDto } from './dto/update-setting.dto';
import { UpdateUserSettingDto } from './dto/update-user-setting.dto';
import { Setting } from './entity/setting.entity';
import { UserSetting } from './entity/user-setting.entity';

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

  constructor(
    @InjectRepository(Setting)
    private readonly settingRepository: Repository<Setting>,
    @InjectRepository(UserSetting)
    private readonly userSettingRepository: Repository<UserSetting>,
  ) { }

  /**
   * Gets a limit for a specific user, checking for overrides before defaults.
   * Priority Order:
   * 1. User-specific setting (from `user_settings` table).
   * 2. Global setting (from `app_settings` table).
   * 3. Hardcoded default value provided in the call.
   */
  async getLimitForUser<T extends number>(userId: number, key: string, defaultValue: T): Promise<T> {
    try {
      // 1. Check for a user-specific setting first
      const userSetting = await this.userSettingRepository.findOne({ where: { userId, key } });
      if (userSetting?.value) {
        this.logger.log(`Found user-specific limit for user ${userId}, key ${key}: ${userSetting.value}`);
        return JSON.parse(userSetting.value) as T;
      }

      // 2. If no user setting, check for a global setting
      const globalSetting = await this.settingRepository.findOne({ where: { key } });
      if (globalSetting?.value) {
        this.logger.log(`Found global limit for key ${key}: ${globalSetting.value}`);
        return JSON.parse(globalSetting.value) as T;
      }

      // 3. Fallback to the hardcoded default
      this.logger.warn(`No setting found for key "${key}". Falling back to hardcoded default: ${defaultValue}`);
      return defaultValue;
    } catch (error) {
      this.logger.error(`Error parsing setting for key "${key}". Returning default value.`, error);
      return defaultValue;
    }
  }

  /**
   * Creates or updates a GLOBAL application setting.
   */
  async updateGlobalSetting(updateSettingDto: UpdateSettingDto): Promise<Setting> {
    const { key, value } = updateSettingDto;
    let setting = await this.settingRepository.findOne({ where: { key } });

    if (setting) {
      setting.value = value;
    } else {
      setting = this.settingRepository.create({ key, value });
    }

    this.logger.log(`Updating global setting: ${key} = ${value}`);
    return this.settingRepository.save(setting);
  }

  /**
   * Creates or updates a USER-SPECIFIC setting override.
   */
  async updateUserSetting(updateUserSettingDto: UpdateUserSettingDto): Promise<UserSetting> {
    const { userId, key, value } = updateUserSettingDto;
    let userSetting = await this.userSettingRepository.findOne({ where: { userId, key } });

    if (userSetting) {
      userSetting.value = value;
    } else {
      userSetting = this.userSettingRepository.create(updateUserSettingDto);
    }
    this.logger.log(`Updating user-specific setting for user ${userId}: ${key} = ${value}`);
    return this.userSettingRepository.save(userSetting);
  }

  /**
   * Retrieves all GLOBAL settings.
   */
  async getAllGlobalSettings(): Promise<Setting[]> {
    return this.settingRepository.find();
  }

  /**
   * Retrieves all settings for a specific user.
   */
  async getSettingsForUser(userId: number): Promise<UserSetting[]> {
    return this.userSettingRepository.find({ where: { userId } });
  }

  /**
 * Retrieves all settings (both global and user-specific) in a structured format.
 */
  async getAllSettings(): Promise<{
    globalSettings: Setting[];
    userSettings: UserSetting[];
  }> {
    const [globalSettings, userSettings] = await Promise.all([
      this.settingRepository.find({ order: { key: 'ASC' } }),
      this.userSettingRepository.find({
        order: { userId: 'ASC', key: 'ASC' }
      }),
    ]);

    return {
      globalSettings,
      userSettings,
    };
  }

  //Returns the list of key name of the setting
  getSettingKeyName(): string[] {
    return ['MAX_ORGS_PER_USER', 'MAX_WEBSITES_PER_ORG'];
  }

}