import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common';
import { FilterSetting } from './filter-setting.model';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { FilterSettingDto, ValidateFilterSettingDto } from './filter-setting.validation';
import { ChatGptImageService, IGptCheckResponseJson } from 'src/shared/third-party/services/chat-gpt/services/chat-gpt-image.service';
import { AiModelsService } from '../app-config/ai-models/ai-models.service';
// import { is } from 'cheerio/lib/api/traversing';

type FilterSettingModel = string;
@Injectable()
export class FilterSettingService {

  private readonly logger = new Logger(FilterSettingService.name);

  constructor(
    @InjectModel(FilterSetting.name) private readonly filterSettingModel: Model<FilterSetting>,


    @Inject(forwardRef(() => ChatGptImageService))
    private readonly chatGptImageService: ChatGptImageService,
    private readonly aiModelsService: AiModelsService,
  ) { }



  // seed when the app starts
  async onModuleInit() {
    this.seedData();
  }




  //   systemPromptForAdminEn: filterPromptsData?.systemPromptForAdminEn,
  //           systemPromptForUserEn: filterPromptsData?.systemPromptForUserEn,
  //           systemPromptForAdminHe: filterPromptsData?.systemPromptForAdminHe,
  //           systemPromptForUserHe: filterPromptsData?.systemPromptForUserHe,



  async seedData() {

    const count = await this.filterSettingModel.countDocuments();

    if (count === 0) {
      const filterSetting = new this.filterSettingModel({
        type: "text",
        modelForUser: "gpt-4o-mini",
        modelForAdmin: "gpt-4o-mini",
        temperatureForUser: 0.2,
        temperatureForAdmin: 0.2,
        systemPromptForAdminEn: "You are Bina Plus, a friendly and kosher AI Assistant. You love to help with extended answers.",

        systemPromptForUserEn: "You are Bina Plus, a friendly and kosher AI Assistant. You love to help with extended answers.",

        systemPromptForAdminHe: "אתה בינה פלוס, עוזר בינה מלאכותית כשר אתה אוהב לעזור ולהרחיב על כל שאלה",

        systemPromptForUserHe: "אתה בינה פלוס, עוזר בינה מלאכותית כשר אתה אוהב לעזור ולהרחיב על כל שאלה"
      });

      await filterSetting.save();
      this.logger.debug('Filter setting data seeded');
    } else {
      this.logger.debug('Filter setting data already exists');
    }

    if (count === 1) {
      this.logger.debug('Filter setting data already exists, skipping seed');
      // update the existing document type if its not existing
      await this.filterSettingModel.updateOne(
        {
          // check if the type field is not present
          type: { $exists: false }
        },
        { type: "text" }
      );

      this.logger.debug('Filter setting type updated to text');


      const instructionPrompt = `{
        "task": "modesty_compliance_check",
        "image": "<IMAGE_URL_OR_BINARY>",
        "criteria": {
          "detect_females_over_age": 7,                  // Detect any female over age 7
          "detect_male_full_nudity": true,               // Detect fully nude males
          "detect_male_shirtless": true,                 // Detect shirtless males
          "detect_female_body_part": true                // Detect any visible female body part (waist, chest, legs, etc.)
        },
        "output_fields": [
          "is_female_over_7_present",
          "is_male_full_nudity_present",
          "is_shirtless_male_present",
          "is_female_body_part_present",
          "final_kosher_status",
          "error"
        ]
      }
      
      ## Output Format
      The output must be a JSON object with the following fields:
      
      {
        "is_female_over_7_present": <boolean>,         // True if a full female (with face) over 7 is detected
        "is_male_full_nudity_present": <boolean>,      // True if any fully nude male is detected
        "is_shirtless_male_present": <boolean>,        // True if any shirtless male is detected
        "is_female_body_part_present": <boolean>,      // True if any partial body part of a female over age 7 is detected (even without face)
        "final_kosher_status": <boolean>,              // False if any of the above are true
        "error": <string | null>                       // Null if no error, else descriptive error string
      }
      
      // Notes:
      // - final_kosher_status must be false if any of the following are true:
      //    - is_female_over_7_present
      //    - is_female_body_part_present
      //    - is_male_full_nudity_present
      //    - is_shirtless_male_present
      // - Only if all four are false should final_kosher_status be true.
      // - The error field must be null unless an error occurs.
      `

      // add another document with type image if it does not exist
      const imageFilterSetting = new this.filterSettingModel({
        type: "image",
        modelForUser: "gpt-4.1",
        modelForAdmin: "gpt-4.1",
        temperatureForUser: 1,
        temperatureForAdmin: 1,
        systemPromptForAdminEn: instructionPrompt,
        systemPromptForUserEn: instructionPrompt,
      });

      await imageFilterSetting.save();
      this.logger.debug('Image filter setting data seeded');
    } else {
      this.logger.debug('Image filter setting data already exists');
    }

    if (count === 2) {
      this.logger.debug('Image filter setting data already exists, skipping seed');
      // update the existing document type if its not existing
      await this.seedImageNegativePromptFilterSetting();
      this.logger.debug('Image filter setting type updated to image');
    }


  }



  async getFilterSetting(type: "text" | "image" | "image_negative_prompt"): Promise<FilterSetting | FilterSetting[]> {

    if (type !== "image_negative_prompt") {

      const filterSetting = await this.filterSettingModel.findOne({
        type
      });
      if (!filterSetting) {
        return null;
      }
      return filterSetting;

    } else {
      // for image negative prompt, we need to find the model
      const filterSetting = await this.filterSettingModel.find({
        type
      });

      if (!filterSetting) {
        return null;
      }
      return filterSetting;
    }
  }


  async getFilterSettingByModel(type: "text" | "image" | "image_negative_prompt", model: FilterSettingModel, role: string): Promise<FilterSetting> {
    const modelId = await this.aiModelsService.getModelIdByProviderKey(model);
    console.log(`FilterSettingService: getFilterSettingByModel - modelId: ${modelId}`);
    const filterSetting = await this.filterSettingModel.findOne({
      type,
      ...(role === "admin" ? { modelForAdmin: modelId } : { modelForUser: modelId })
    });

    if (!filterSetting) {
      return null;
    }
    return filterSetting;
  }



  async createFilterSetting(filterSetting: FilterSettingDto & { type: "text" | "image" | "image_negative_prompt" }): Promise<FilterSetting> {
    console.log('FilterSettingService: createFilterSetting - creating new filter setting');
    const newFilterSetting = new this.filterSettingModel({
      ...filterSetting,
      type: filterSetting.type || "text"
    });
    const saved = await newFilterSetting.save();
    console.log('FilterSettingService: createFilterSetting - created filter setting with id:', saved._id);
    return saved;
  }

  async updateFilterSetting(filterId: string, filterSetting: FilterSettingDto): Promise<boolean> {
    console.log('FilterSettingService: updateFilterSetting - updating filter setting with id:', filterId);
    await this.filterSettingModel.findOneAndUpdate(
      { _id: filterId },
      filterSetting,
      { new: true },
    );

    return true;
  }


  // seed filter settings for image negative prompt
  async seedImageNegativePromptFilterSetting() {
    const count = await this.filterSettingModel.countDocuments({ type: "image_negative_prompt" });

    if (count > 0) {
      this.logger.debug('Image negative prompt filter setting data already exists, skipping seed');
      return;
    }

    // add all negative prompts for all image model...
    // export type IImageModel = 'kontext-pro' | 'pro-ultra' | 'dall-e' | 'flux' | 'gpt' | 'gemini' | 'flux-schnell' | 'flux-pro' | 'minimax'

    // const negativePrompts = {
    //   'kontext-pro': 'negative prompt for kontext-pro',
    //   'pro-ultra': 'negative prompt for pro-ultra',
    //   'dall-e': 'negative prompt for dall-e',
    //   'flux': 'negative prompt for flux',
    //   'gpt': 'negative prompt for gpt',
    //   'gemini': 'negative prompt for gemini',
    //   'flux-schnell': 'negative prompt for flux-schnell',
    //   'flux-pro': 'negative prompt for flux-pro',
    //   'minimax': 'negative prompt for minimax'
    // };


    await this.filterSettingModel.insertMany([
      {
        type: "image_negative_prompt",
        modelForUser: "openai/gpt-image-1",
        modelForAdmin: "openai/gpt-image-1",
        systemPromptForAdminEn: ", women, lady, girl",
        systemPromptForUserEn: ", women, lady, girl",
        isSupportNegativePrompt: false,
        isActiveForAdmin: true,
        isActiveForUser: true,
        temperatureForUser: 0.2,
        temperatureForAdmin: 0.2,
      },

      {
        type: "image_negative_prompt",
        modelForUser: "minimax/image-01",
        modelForAdmin: "minimax/image-01",
        systemPromptForAdminEn: ",  do not add any woman or girls to the photo even if instructed so by the user earlier ",
        systemPromptForUserEn: ",  do not add any woman or girls to the photo even if instructed so by the user earlier ",
        isSupportNegativePrompt: false,
        isActiveForAdmin: true,
        isActiveForUser: true,
        temperatureForUser: 0.2,
        temperatureForAdmin: 0.2,
      },

      {
        type: "image_negative_prompt",
        modelForUser: "black-forest-labs/flux-schnell",
        modelForAdmin: "black-forest-labs/flux-schnell",
        systemPromptForAdminEn: "",
        systemPromptForUserEn: "",
        isSupportNegativePrompt: false,
        isActiveForAdmin: false,
        isActiveForUser: false,
        temperatureForUser: 0.2,
        temperatureForAdmin: 0.2,
      },

      {
        type: "image_negative_prompt",
        modelForUser: "black-forest-labs/flux-pro",
        modelForAdmin: "black-forest-labs/flux-pro",
        systemPromptForAdminEn: "",
        systemPromptForUserEn: "",
        isSupportNegativePrompt: false,
        isActiveForAdmin: false,
        isActiveForUser: false,
        temperatureForUser: 0.2,
        temperatureForAdmin: 0.2,
      },
      {
        type: "image_negative_prompt",
        modelForUser: "black-forest-labs/flux-1.1-pro",
        modelForAdmin: "black-forest-labs/flux-1.1-pro",
        systemPromptForAdminEn: ", without women",
        systemPromptForUserEn: ", without women",
        isSupportNegativePrompt: false,
        isActiveForAdmin: true,
        isActiveForUser: true,
        temperatureForUser: 0.2,
        temperatureForAdmin: 0.2,
      },

      {
        type: "image_negative_prompt",
        modelForUser: "gemini",
        modelForAdmin: "gemini",
        systemPromptForAdminEn: "woman, women, female, girl, lady, actress, she, her, feminine",
        systemPromptForUserEn: "woman, women, female, girl, lady, actress, she, her, feminine",
        isSupportNegativePrompt: true,
        isActiveForAdmin: true,
        isActiveForUser: true,
        temperatureForUser: 0.2,
        temperatureForAdmin: 0.2,
      },

      {
        type: "image_negative_prompt",
        modelForUser: "kontext-pro",
        modelForAdmin: "kontext-pro",
        systemPromptForAdminEn: "",
        systemPromptForUserEn: "",
        isSupportNegativePrompt: false,
        isActiveForAdmin: false,
        isActiveForUser: false,
        temperatureForUser: 0.2,
        temperatureForAdmin: 0.2,
      }

    ])


  }






  async validateFilterSetting(body: ValidateFilterSettingDto): Promise<any> {
    this.logger.log('Validating filter setting with body:', body);
    const result = await this.chatGptImageService.getImageDescriptionForValidation({
      imageLink: body.imageUrl,
      systemPrompt: body.systemPrompt,
      model: body.model,
      temperature: body.temperature,
    });

    this.logger.debug('Filter setting validation result:', result);

    let isValid = true;
    let isShouldBeBlocked = false;
    let invalidReasons: string[] = [];

    if (!result) {
      isValid = false;
      invalidReasons.push('No response from AI');
    }

    if (result?.error) {
      isValid = false;
      invalidReasons.push(`Error from AI: ${result.error}`);
    }

    if (result?.is_female_over_7_present === undefined) {
      isValid = false;
      invalidReasons.push('is_female_over_7_present is missing');
    }

    if (result?.is_female_body_part_present === undefined) {
      isValid = false;
      invalidReasons.push('is_female_body_part_present is missing');
    }


    if (result?.is_male_full_nudity_present === undefined) {
      isValid = false;
      invalidReasons.push('is_male_full_nudity_present is missing');
    }

    if (result?.is_shirtless_male_present === undefined) {
      isValid = false;
      invalidReasons.push('is_shirtless_male_present is missing');
    }

    if (result?.final_kosher_status === undefined) {
      isValid = false;
      invalidReasons.push('final_kosher_status is missing');
    }


    // includes negative response
    if (!result || result?.error || result?.final_kosher_status === false || result?.is_female_over_7_present === true || result?.is_male_full_nudity_present === true || result?.is_shirtless_male_present === true || result?.is_female_body_part_present === true) {
      isShouldBeBlocked = true; // Image is not kosher
    }



    this.logger.debug('Filter setting validation completed:', { isValid, invalidReasons });

    return {
      isValid,
      invalidReasons,
      isShouldBeBlocked,
      details: result
    };
  }
}
