import { createAction, Property } from '@activepieces/pieces-framework';
import { InferenceClient } from '@huggingface/inference';
import type { TextToImageInput } from '@huggingface/tasks';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { huggingFaceAuth } from '../auth';

export const createImage = createAction({
  audience: 'human',
  name: 'create_image',
  auth: huggingFaceAuth,
  displayName: 'Create Image',
  description:
    'Generate stunning images from text prompts using state-of-the-art diffusion models - perfect for marketing, product design, and creative content',
  props: {
    useCase: Property.StaticDropdown({
      displayName: 'Use Case',
      description: 'What type of image generation do you need?',
      required: true,
      options: {
        disabled: false,
        options: [
          {
            label: 'Fast Generation (Quick Prototypes)',
            value: 'speed',
          },
          {
            label: 'High Quality (Marketing & Print)',
            value: 'quality',
          },
          {
            label: 'Business Content (Products & Brands)',
            value: 'business',
          },
          {
            label: 'Search All Models',
            value: 'search',
          },
        ],
      },
      defaultValue: 'quality',
    }),
    model: Property.Dropdown({
      displayName: 'Image Generation Model',
      description: 'Select the best model for your use case',
      required: true,
      refreshers: ['useCase'],    
      auth: huggingFaceAuth,
      options: async ({ useCase }) => {
        const getModelsByUseCase = (type: string) => {
          switch (type) {
            case 'speed':
              return [
                {
                  label: 'FLUX.1 Schnell (⚡ Ultra Fast - 1-4 steps)',
                  value: 'black-forest-labs/FLUX.1-schnell',
                  description: '634K downloads | Best for rapid prototyping',
                },
                {
                  label: 'SD Turbo (⚡ Real-time - 1 step)',
                  value: 'stabilityai/sd-turbo',
                  description: '1.2M downloads | Fastest generation',
                },
                {
                  label: 'SDXL Turbo (⚡ Fast - 1-4 steps)',
                  value: 'stabilityai/sdxl-turbo',
                  description: '223K downloads | Fast with good quality',
                },
              ];
            case 'quality':
              return [
                {
                  label: 'FLUX.1 Dev (Premium Quality)',
                  value: 'black-forest-labs/FLUX.1-dev',
                  description: '1.4M downloads | State-of-the-art results',
                },
                {
                  label: 'Stable Diffusion XL (🎯 Reliable Quality)',
                  value: 'stabilityai/stable-diffusion-xl-base-1.0',
                  description: '2.2M downloads | Industry standard',
                },
                {
                  label: 'SD 3 Medium (🔬 Advanced Features)',
                  value: 'stabilityai/stable-diffusion-3-medium',
                  description: '13K downloads | Latest technology',
                },
              ];
            case 'business':
              return [
                {
                  label: 'Stable Diffusion XL (💼 Professional)',
                  value: 'stabilityai/stable-diffusion-xl-base-1.0',
                  description: '2.2M downloads | Business-ready quality',
                },
                {
                  label: 'DreamShaper v7 (🎨 Versatile Style)',
                  value: 'Lykon/dreamshaper-7',
                  description: '833K downloads | Great for varied content',
                },
                {
                  label: 'OpenJourney (🌟 Midjourney Style)',
                  value: 'prompthero/openjourney',
                  description: '8K downloads | Artistic business content',
                },
              ];
            default:
              return [];
          }
        };

        if (useCase === 'search') {
          try {
            const response = await httpClient.sendRequest({
              method: HttpMethod.GET,
              url: 'https://huggingface.co/api/models?pipeline_tag=text-to-image&sort=downloads&limit=50',
            });

            const models = response.body as Array<{
              id: string;
              downloads: number;
              likes: number;
            }>;

            return {
              disabled: false,
              placeholder: 'Select from 50+ popular models...',
              options: models
                .filter((model) => model.downloads > 50000)
                .slice(0, 20)
                .map((model) => ({
                  label: `${model.id} (${(model.downloads / 1000).toFixed(
                    0
                  )}K downloads)`,
                  value: model.id,
                })),
            };
          } catch (error) {
            return {
              disabled: false,
              options: getModelsByUseCase('quality'),
            };
          }
        }

        return {
          disabled: false,
          options: getModelsByUseCase(useCase as string),
        };
      },
    }),
    prompt: Property.LongText({
      displayName: 'Text Prompt',
      description:
        'Describe the image you want to generate. Be specific about style, colors, composition, and details.',
      required: true,
      defaultValue: '',
    }),
    aspectRatio: Property.StaticDropdown({
      displayName: 'Aspect Ratio',
      description: 'Choose the dimensions for your image',
      required: false,
      options: {
        disabled: false,
        options: [
          { label: '📱 Portrait (512×768) - Social Media', value: 'portrait' },
          { label: '🖥️ Landscape (768×512) - Banners', value: 'landscape' },
          { label: '⬜ Square (512×512) - Profile Pictures', value: 'square' },
          { label: '📺 Wide (1024×576) - Headers', value: 'wide' },
          { label: '⚙️ Custom Dimensions', value: 'custom' },
        ],
      },
      defaultValue: 'square',
    }),
    customWidth: Property.Number({
      displayName: 'Custom Width',
      description: 'Width in pixels (64-1024)',
      required: false,
    }),
    customHeight: Property.Number({
      displayName: 'Custom Height',
      description: 'Height in pixels (64-1024)',
      required: false,
    }),
    negativePrompt: Property.LongText({
      displayName: 'Negative Prompt',
      description:
        "Describe what you DON'T want in the image (blur, low quality, distorted, etc.)",
      required: false,
    }),
    qualitySettings: Property.StaticDropdown({
      displayName: 'Quality vs Speed',
      description: 'Balance between image quality and generation time',
      required: false,
      options: {
        disabled: false,
        options: [
          { label: '⚡ Fast (10-20 steps)', value: 'fast' },
          { label: '⚖️ Balanced (20-30 steps)', value: 'balanced' },
          { label: '🎯 High Quality (30-50 steps)', value: 'quality' },
          { label: '🏆 Maximum Quality (50+ steps)', value: 'maximum' },
          { label: '⚙️ Custom Steps', value: 'custom' },
        ],
      },
      defaultValue: 'balanced',
    }),
    customSteps: Property.Number({
      displayName: 'Custom Inference Steps',
      description: 'Number of denoising steps (1-100)',
      required: false,
    }),
    guidanceScale: Property.Number({
      displayName: 'Guidance Scale',
      description:
        'How closely to follow the prompt (1-20). Higher values = more prompt adherence but may reduce creativity.',
      required: false,
      defaultValue: 7.5,
    }),
    seed: Property.Number({
      displayName: 'Seed (Optional)',
      description:
        'Set a seed for reproducible results. Leave empty for random generation.',
      required: false,
    }),
    scheduler: Property.StaticDropdown({
      displayName: 'Scheduler',
      description: 'Advanced: Choose the noise scheduler algorithm',
      required: false,
      options: {
        disabled: false,
        options: [
          { label: 'DPM++ 2M Karras (Recommended)', value: 'DPM++2MKarras' },
          { label: 'Euler A (Fast)', value: 'EulerA' },
          { label: 'DDIM (Stable)', value: 'DDIM' },
          { label: 'LMS (Classic)', value: 'LMS' },
        ],
      },
    }),
  },
  async run(context) {
    const {
      useCase,
      model,
      prompt,
      aspectRatio,
      customWidth,
      customHeight,
      negativePrompt,
      qualitySettings,
      customSteps,
      guidanceScale,
      seed,
      scheduler,
    } = context.propsValue;

    if (!prompt?.trim()) {
      throw new Error('Please provide a text prompt for image generation');
    }

    let width: number, height: number;
    switch (aspectRatio) {
      case 'portrait':
        width = 512;
        height = 768;
        break;
      case 'landscape':
        width = 768;
        height = 512;
        break;
      case 'square':
        width = 512;
        height = 512;
        break;
      case 'wide':
        width = 1024;
        height = 576;
        break;
      case 'custom':
        width = customWidth || 512;
        height = customHeight || 512;
        break;
      default:
        width = 512;
        height = 512;
    }

    let numInferenceSteps: number;
    switch (qualitySettings) {
      case 'fast':
        numInferenceSteps = 15;
        break;
      case 'balanced':
        numInferenceSteps = 25;
        break;
      case 'quality':
        numInferenceSteps = 40;
        break;
      case 'maximum':
        numInferenceSteps = 60;
        break;
      case 'custom':
        numInferenceSteps = customSteps || 25;
        break;
      default:
        numInferenceSteps = 25;
    }

    const hf = new InferenceClient(context.auth.secret_text);

    // Build parameters object
    const parameters: Record<string, unknown> = {
      guidance_scale: guidanceScale || 7.5,
      num_inference_steps: numInferenceSteps,
      width: width,
      height: height,
    };

    if (negativePrompt?.trim()) {
      parameters['negative_prompt'] = negativePrompt.trim();
    }

    if (seed !== undefined && seed !== null) {
      parameters['seed'] = Math.floor(seed);
    }

    if (scheduler) {
      parameters['scheduler'] = scheduler;
    }

    const args: TextToImageInput = {
      model: model,
      inputs: prompt.trim(),
      parameters: parameters,
    };

    const startTime = Date.now();

    try {
      const imageBlob = await hf.textToImage(args, {
        retry_on_error: true,
      });

      if (!(imageBlob instanceof Blob)) {
        throw new Error('Expected Blob response from text-to-image API');
      }

      const imageBuffer = Buffer.from(await imageBlob.arrayBuffer());
      const base64Image = imageBuffer.toString('base64');

      const generationTime = (Date.now() - startTime) / 1000;
      const imageSizeKB = Math.round(imageBuffer.length / 1024);

      return {
        image: base64Image,
        imageData: {
          format: 'PNG',
          width: width,
          height: height,
          sizeKB: imageSizeKB,
          base64: `data:image/png;base64,${base64Image}`,
        },
        generation: {
          prompt: prompt.trim(),
          negativePrompt: negativePrompt?.trim() || '',
          model: model,
          useCase: useCase,
        },
        parameters: {
          width: width,
          height: height,
          aspectRatio: aspectRatio,
          guidanceScale: guidanceScale || 7.5,
          inferenceSteps: numInferenceSteps,
          scheduler: scheduler || 'auto',
          seed: seed || 'random',
        },
        metrics: {
          generationTimeSeconds: generationTime,
          imageSizeKB: imageSizeKB,
          resolution: `${width}×${height}`,
          qualitySetting: qualitySettings || 'balanced',
          estimatedCost: calculateEstimatedCost(
            model,
            width,
            height,
            numInferenceSteps
          ),
        },
        businessInsights: {
          useCase: getUseCaseDescription(useCase as string),
          qualityTips: getQualityTips(
            prompt,
            negativePrompt,
            numInferenceSteps
          ),
          nextSteps: getNextSteps(useCase as string, imageSizeKB),
        },
        rawResult: {
          blob: imageBlob,
          generationTime: generationTime,
        },
      };
    } catch (error: unknown) {
      const errorMessage =
        error instanceof Error ? error.message : String(error);
      throw new Error(`Image generation failed: ${errorMessage}`);
    }
  },
});

function getUseCaseDescription(useCase: string): string {
  const descriptions = {
    speed: 'Optimized for rapid prototyping and quick content creation',
    quality:
      'High-resolution generation perfect for marketing and professional use',
    business:
      'Business-focused models ideal for product imagery and brand content',
    search: 'Custom model selection for specialized requirements',
  };

  return (
    descriptions[useCase as keyof typeof descriptions] ||
    'AI-powered image generation'
  );
}

function getQualityTips(
  prompt: string,
  negativePrompt: string | undefined,
  steps: number
): string[] {
  const tips: string[] = [];

  if (prompt.length < 20) {
    tips.push(
      '💡 Add more descriptive details to your prompt for better results'
    );
  }

  if (!negativePrompt) {
    tips.push(
      '🚫 Consider adding negative prompts to avoid unwanted elements (blur, low quality, etc.)'
    );
  }

  if (steps < 20) {
    tips.push(
      '⚡ Using fast generation - increase steps for higher quality if needed'
    );
  }

  if (steps > 50) {
    tips.push(
      '⏱️ High step count may take longer - consider balanced setting for faster results'
    );
  }

  if (
    !prompt.toLowerCase().includes('high quality') &&
    !prompt.toLowerCase().includes('detailed')
  ) {
    tips.push(
      '🎯 Add quality keywords like "high resolution", "detailed", or "professional" to your prompt'
    );
  }

  if (tips.length === 0) {
    tips.push('✅ Good generation parameters - expect quality results');
  }

  return tips;
}


function getNextSteps(useCase: string, imageSizeKB: number): string[] {
  const steps: string[] = [];

  if (useCase === 'business') {
    steps.push('🎨 Try variations with different styles or angles');
    steps.push(
      '📐 Consider generating multiple aspect ratios for different platforms'
    );
  }

  if (useCase === 'speed') {
    steps.push('🔄 Generate variations quickly with different seeds');
    steps.push(
      '⬆️ Upscale to higher quality when you find the perfect concept'
    );
  }

  if (imageSizeKB > 1000) {
    steps.push('📉 Consider optimizing image size for web use');
  }

  steps.push('💾 Save successful prompts for consistent brand imagery');
  steps.push('🔄 Use the same seed to create variations of this concept');

  return steps;
}

function calculateEstimatedCost(
  model: string,
  width: number,
  height: number,
  steps: number
): string {
  const basePixelCost = 0.000001;
  const stepMultiplier = steps / 25;
  const modelMultiplier = model.includes('FLUX.1-dev')
    ? 2.5
    : model.includes('stable-diffusion-3')
    ? 2.0
    : model.includes('turbo')
    ? 0.5
    : 1.0;

  const pixels = width * height;
  const estimatedCost =
    pixels * basePixelCost * stepMultiplier * modelMultiplier;

  if (estimatedCost < 0.001) {
    return '< $0.001';
  }

  return `~$${estimatedCost.toFixed(4)}`;
}
