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

export const chatCompletion = createAction({
  audience: 'human',
  name: 'chat_completion',
  auth: huggingFaceAuth,
  displayName: 'Chat Completion',
  description:
    'Generate assistant replies using chat-style LLMs - perfect for FAQ bots, support agents, and content generation',
  props: {
    useCase: Property.StaticDropdown({
      displayName: 'Use Case',
      description: 'What type of chat assistant are you building?',
      required: true,
      options: {
        disabled: false,
        options: [
          {
            label: 'FAQ & Customer Support',
            value: 'faq',
          },
          {
            label: 'Content Generation & Writing',
            value: 'content',
          },
          {
            label: 'General Conversation',
            value: 'chat',
          },
          {
            label: 'Search All Models',
            value: 'search',
          },
        ],
      },
      defaultValue: 'faq',
    }),
    model: Property.Dropdown({
      auth: huggingFaceAuth,  
      displayName: 'Chat Model',
      description: 'Select the best model for your use case',
      required: true,
      refreshers: ['useCase'],
      options: async ({ auth, useCase }) => {
        // Define model options based on use case
        const getModelsByUseCase = (type: string) => {
          switch (type) {
            case 'faq':
              return [
                {
                  label:
                    'Llama-3.2-1B (3.3M downloads) - Fast FAQ responses',
                  value: 'meta-llama/Llama-3.2-1B-Instruct',
                },
                {
                  label: 'Qwen2.5-1.5B (3M downloads) - Efficient support',
                  value: 'Qwen/Qwen2.5-1.5B-Instruct',
                },
                {
                  label: 'Gemma-3-1B (2.6M downloads) - Google optimized',
                  value: 'google/gemma-3-1b-it',
                },
                {
                  label: 'FAQ ChatBot (E-commerce specialist)',
                  value: 'Alkyema/FAQ_ChatBot',
                },
              ];
            case 'content':
              return [
                {
                  label: 'Llama-3.1-8B (14.2M downloads) - High quality',
                  value: 'meta-llama/Llama-3.1-8B-Instruct',
                },
                {
                  label: 'Qwen2.5-7B (9.1M downloads) - Great balance',
                  value: 'Qwen/Qwen2.5-7B-Instruct',
                },
                {
                  label: 'Qwen2.5-14B (12.2M downloads) - Best quality',
                  value: 'Qwen/Qwen2.5-14B-Instruct',
                },
                {
                  label: 'OpenAI GPT-OSS-20B (3.7M downloads) - Creative',
                  value: 'openai/gpt-oss-20b',
                },
              ];
            case 'chat':
              return [
                {
                  label: 'Qwen2.5-7B (9.1M downloads) - Best overall',
                  value: 'Qwen/Qwen2.5-7B-Instruct',
                },
                {
                  label: 'Llama-3.2-1B (3.3M downloads) - Fast responses',
                  value: 'meta-llama/Llama-3.2-1B-Instruct',
                },
                {
                  label: 'Qwen2.5-1.5B (3M downloads) - Efficient',
                  value: 'Qwen/Qwen2.5-1.5B-Instruct',
                },
                {
                  label: 'Gemma-3-1B (2.6M downloads) - Reliable',
                  value: 'google/gemma-3-1b-it',
                },
              ];
            default:
              return [
                {
                  label: 'Qwen2.5-7B (9.1M downloads)',
                  value: 'Qwen/Qwen2.5-7B-Instruct',
                },
              ];
          }
        };

        // Return use case-specific models for non-search types
        if (useCase !== 'search') {
          return {
            disabled: false,
            options: getModelsByUseCase((useCase as string) || 'faq'),
          };
        }

        // Handle search mode - load all conversational models
        const popularModels = [
          {
            label: 'Meta Llama-3.1-8B (14.2M downloads)',
            value: 'meta-llama/Llama-3.1-8B-Instruct',
          },
          {
            label: 'Qwen2.5-7B (9.1M downloads)',
            value: 'Qwen/Qwen2.5-7B-Instruct',
          },
          {
            label: 'Llama-3.2-1B (3.3M downloads)',
            value: 'meta-llama/Llama-3.2-1B-Instruct',
          },
        ];

        if (!auth) {
          return {
            disabled: false,
            options: popularModels,
          };
        }

        try {
          const response = await httpClient.sendRequest({
            method: HttpMethod.GET,
            url: 'https://huggingface.co/api/models',
            queryParams: {
              filter: 'conversational',
              sort: 'downloads',
              direction: '-1',
              limit: '100',
            },
          });

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

          const conversationalModels = models
            .filter(
              (model) =>
                model.pipeline_tag === 'conversational' ||
                model.pipeline_tag === 'text-generation'
            )
            .map((model) => ({
              label: `${model.id} (${
                model.downloads?.toLocaleString() || 0
              } downloads)`,
              value: model.id,
            }))
            .slice(0, 50);

          const allOptions = [
            ...popularModels,
            ...conversationalModels.filter(
              (model) =>
                !popularModels.some((popular) => popular.value === model.value)
            ),
          ];

          return {
            disabled: false,
            options: allOptions,
          };
        } catch (error) {
          return {
            disabled: false,
            options: popularModels,
          };
        }
      },
      defaultValue: 'meta-llama/Llama-3.2-1B-Instruct',
    }),
    conversationMode: Property.StaticDropdown({
      displayName: 'Conversation Mode',
      description: 'How do you want to build the conversation?',
      required: true,
      options: {
        disabled: false,
        options: [
          {
            label: 'Single Message (Simple Q&A)',
            value: 'single',
          },
          {
            label: 'Multi-turn Conversation',
            value: 'multi',
          },
          {
            label: 'Template-based Response',
            value: 'template',
          },
        ],
      },
      defaultValue: 'single',
    }),
    userMessage: Property.LongText({
      displayName: 'User Message',
      description: 'The user message or question to respond to',
      required: false,
    }),
    systemPrompt: Property.LongText({
      displayName: 'System Prompt (Optional)',
      description: 'Instructions for how the assistant should behave',
      required: false,
    }),
    conversationHistory: Property.Array({
      displayName: 'Conversation History',
      description:
        'Previous messages in the conversation (for multi-turn chat)',
      required: false,
    }),
    template: Property.StaticDropdown({
      displayName: 'Response Template',
      description: 'Pre-built templates for common business scenarios',
      required: false,
      options: {
        disabled: false,
        options: [
          {
            label: 'Customer Support Agent',
            value: 'support',
          },
          {
            label: 'FAQ Assistant',
            value: 'faq',
          },
          {
            label: 'Content Writer',
            value: 'writer',
          },
          {
            label: 'Email Responder',
            value: 'email',
          },
          {
            label: 'E-commerce Assistant',
            value: 'ecommerce',
          },
        ],
      },
    }),
    responseLength: Property.StaticDropdown({
      displayName: 'Response Length',
      description: 'How long should the response be?',
      required: false,
      options: {
        disabled: false,
        options: [
          { label: 'Brief (50-100 tokens)', value: 'brief' },
          { label: 'Normal (100-200 tokens)', value: 'normal' },
          { label: 'Detailed (200-400 tokens)', value: 'detailed' },
          { label: 'Custom', value: 'custom' },
        ],
      },
      defaultValue: 'normal',
    }),
    customMaxTokens: Property.Number({
      displayName: 'Custom Max Tokens',
      description: 'Maximum number of tokens to generate',
      required: false,
    }),
    temperature: Property.Number({
      displayName: 'Creativity Level',
      description:
        'How creative should responses be? (0.1 = focused, 1.0 = creative)',
      required: false,
      defaultValue: 0.7,
    }),
    topP: Property.Number({
      displayName: 'Response Variety',
      description: 'Controls response diversity (0.1 = focused, 1.0 = varied)',
      required: false,
      defaultValue: 0.9,
    }),
    stopSequences: Property.Array({
      displayName: 'Stop Sequences (Optional)',
      description: 'Text sequences that will stop generation',
      required: false,
    }),
    frequencyPenalty: Property.Number({
      displayName: 'Repetition Penalty',
      description: 'Reduce repetitive responses (-2.0 to 2.0)',
      required: false,
      defaultValue: 0.0,
    }),
    presencePenalty: Property.Number({
      displayName: 'Topic Diversity',
      description: 'Encourage diverse topics (-2.0 to 2.0)',
      required: false,
      defaultValue: 0.0,
    }),
    useCache: Property.Checkbox({
      displayName: 'Use Cache',
      description: 'Use cached responses for identical requests',
      required: false,
      defaultValue: true,
    }),
    waitForModel: Property.Checkbox({
      displayName: 'Wait for Model',
      description: 'Wait for model to load if not immediately available',
      required: false,
      defaultValue: false,
    }),
  },
  async run(context) {
    const {
      useCase,
      model,
      conversationMode,
      userMessage,
      systemPrompt,
      conversationHistory,
      template,
      responseLength,
      customMaxTokens,
      temperature,
      topP,
      stopSequences,
      frequencyPenalty,
      presencePenalty,
    } = context.propsValue;

    const messages: Array<{ role: string; content: string }> = [];

    const systemMessage = getSystemPrompt(
      template,
      systemPrompt,
      useCase as string
    );
    if (systemMessage) {
      messages.push({ role: 'system', content: systemMessage });
    }

    switch (conversationMode) {
      case 'single':
        if (!userMessage?.trim()) {
          throw new Error(
            'Please provide a user message for single message mode'
          );
        }
        messages.push({ role: 'user', content: userMessage.trim() });
        break;

      case 'multi':
        // Add conversation history
        if (conversationHistory && Array.isArray(conversationHistory)) {
          const historyMessages = conversationHistory
            .filter(
              (msg: unknown): msg is { role: string; content: string } => {
                if (!msg || typeof msg !== 'object' || msg === null) {
                  return false;
                }
                const msgObj = msg as Record<string, unknown>;
                return (
                  'role' in msgObj &&
                  'content' in msgObj &&
                  typeof msgObj['role'] === 'string' &&
                  typeof msgObj['content'] === 'string'
                );
              }
            )
            .map((msg) => ({
              role: msg['role'] as string,
              content: msg['content'] as string,
            }));
          messages.push(...historyMessages);
        }

        if (userMessage?.trim()) {
          messages.push({ role: 'user', content: userMessage.trim() });
        }
        break;

      case 'template':
        if (!userMessage?.trim()) {
          throw new Error('Please provide a user message for template mode');
        }
        messages.push({ role: 'user', content: userMessage.trim() });
        break;

      default:
        if (!userMessage?.trim()) {
          throw new Error('Please provide a user message');
        }
        messages.push({ role: 'user', content: userMessage.trim() });
    }

    if (messages.length === 0) {
      throw new Error('No messages provided for the conversation');
    }

    let maxTokens: number;
    switch (responseLength) {
      case 'brief':
        maxTokens = 100;
        break;
      case 'normal':
        maxTokens = 200;
        break;
      case 'detailed':
        maxTokens = 400;
        break;
      case 'custom':
        maxTokens = customMaxTokens || 200;
        break;
      default:
        maxTokens = 200;
    }

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

    const args: ChatCompletionInput = {
      model: model,
      messages: messages,
      max_tokens: maxTokens,
      temperature: temperature || 0.7,
      top_p: topP || 0.9,
      stream: false,
    };

    if (
      stopSequences &&
      Array.isArray(stopSequences) &&
      stopSequences.length > 0
    ) {
      const validStopSequences = stopSequences.filter(
        (seq): seq is string => typeof seq === 'string' && seq.trim().length > 0
      );
      if (validStopSequences.length > 0) {
        args.stop = validStopSequences;
      }
    }

    if (frequencyPenalty !== undefined && frequencyPenalty !== 0) {
      args.frequency_penalty = frequencyPenalty;
    }

    if (presencePenalty !== undefined && presencePenalty !== 0) {
      args.presence_penalty = presencePenalty;
    }

    const chatResult = await hf.chatCompletion(args);

    const assistantMessage = chatResult.choices?.[0]?.message?.content || '';
    const finishReason = chatResult.choices?.[0]?.finish_reason || 'unknown';

    const userMessageLength = userMessage?.length || 0;
    const assistantMessageLength = assistantMessage.length;
    const tokenUsage = chatResult.usage;

    return {
      response: assistantMessage,
      conversation: {
        userMessage: userMessage || '',
        assistantMessage: assistantMessage,
        fullConversation: [
          ...messages,
          { role: 'assistant', content: assistantMessage },
        ],
      },
      metadata: {
        model: model,
        useCase: useCase,
        conversationMode: conversationMode,
        template: template || 'none',
        finishReason: finishReason,
      },
      metrics: {
        userMessageLength: userMessageLength,
        responseLength: assistantMessageLength,
        tokensUsed: tokenUsage?.total_tokens || 0,
        promptTokens: tokenUsage?.prompt_tokens || 0,
        completionTokens: tokenUsage?.completion_tokens || 0,
        estimatedCost: calculateEstimatedCost(
          model,
          tokenUsage?.total_tokens || 0
        ),
      },
      businessInsights: {
        useCase: getUseCaseDescription(useCase as string),
        qualityTips: getQualityTips(assistantMessage, finishReason),
        nextSteps: getNextSteps(conversationMode, finishReason),
      },
      rawResult: chatResult,
    };
  },
});

function getSystemPrompt(
  template: string | undefined,
  customPrompt: string | undefined,
  useCase: string
): string {
  if (customPrompt?.trim()) {
    return customPrompt.trim();
  }

  const templates = {
    support:
      "You are a helpful customer support agent. Be empathetic, professional, and solution-focused. Always acknowledge the customer's concern and provide clear, actionable steps to resolve their issue.",
    faq: "You are an FAQ assistant. Provide concise, accurate answers to common questions. If you don't know the answer, politely suggest contacting support or checking documentation.",
    writer:
      'You are a professional content writer. Create engaging, well-structured content that is clear, informative, and appropriate for the target audience. Use proper grammar and formatting.',
    email:
      "You are an email response assistant. Write professional, courteous emails that address the recipient's needs clearly and concisely. Include appropriate greetings and closings.",
    ecommerce:
      'You are an e-commerce assistant. Help customers with product information, orders, shipping, and returns. Be knowledgeable about products and policies while maintaining a friendly, sales-oriented approach.',
  };

  if (template && template in templates) {
    return templates[template as keyof typeof templates];
  }

  const defaultPrompts = {
    faq: 'You are a helpful FAQ assistant. Provide clear, concise answers to user questions.',
    content:
      'You are a professional content creator. Generate high-quality, engaging content based on user requests.',
    chat: 'You are a helpful and friendly AI assistant. Provide helpful responses while being conversational and engaging.',
  };

  return (
    defaultPrompts[useCase as keyof typeof defaultPrompts] ||
    'You are a helpful AI assistant.'
  );
}

function getUseCaseDescription(useCase: string): string {
  const descriptions = {
    faq: 'Perfect for answering frequently asked questions and providing customer support',
    content:
      'Ideal for content creation, writing assistance, and creative projects',
    chat: 'Great for general conversation and interactive assistance',
    search: 'Custom model selection for specialized chat requirements',
  };

  return (
    descriptions[useCase as keyof typeof descriptions] ||
    'General purpose chat assistance'
  );
}

function getQualityTips(response: string, finishReason: string): string[] {
  const tips: string[] = [];

  if (response.length < 20) {
    tips.push(
      '⚠️ Response is very short - consider using Normal or Detailed length'
    );
  }

  if (response.length > 1000) {
    tips.push(
      '📝 Very long response - consider using Brief or Normal length for better user experience'
    );
  }

  if (finishReason === 'length') {
    tips.push(
      '✂️ Response was truncated - increase max tokens for complete responses'
    );
  }

  if (finishReason === 'stop') {
    tips.push(
      '🛑 Response stopped at stop sequence - this is expected behavior'
    );
  }

  if (response.includes("I don't know") || response.includes('I cannot')) {
    tips.push(
      '🎯 Consider providing more context or using a template with better instructions'
    );
  }

  if (tips.length === 0) {
    tips.push('✅ Good response quality achieved');
  }

  return tips;
}

function getNextSteps(
  conversationMode: string,
  finishReason: string
): string[] {
  const steps: string[] = [];

  if (conversationMode === 'single') {
    steps.push('💡 Switch to Multi-turn mode for follow-up conversations');
  }

  if (conversationMode === 'multi') {
    steps.push('🔄 Add this response to conversation history for context');
  }

  if (finishReason === 'length') {
    steps.push('⚙️ Increase max tokens or use Detailed response length');
  }

  steps.push('📊 Monitor token usage for cost optimization');
  steps.push('🎯 Fine-tune temperature and penalties for better responses');

  return steps;
}

function calculateEstimatedCost(model: string, totalTokens: number): string {
  const costPer1M = model.includes('llama-3.1-8b')
    ? 0.6
    : model.includes('qwen')
    ? 0.3
    : model.includes('gemma')
    ? 0.25
    : 0.5;

  const estimatedCost = (totalTokens / 1000000) * costPer1M;

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

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