/**
 * Webhook Provisioning Service
 * Automates webhook setup for new user accounts
 *
 * This service handles:
 * - Generating unique webhook tokens
 * - Deploying N8N workflows via N8N API
 * - Configuring WhatsApp routing
 * - Setting up voice agent connections
 * - Creating initial workflow records
 */

import { prisma } from '@/lib/db';
import { randomBytes, createHash } from 'crypto';
import { systemSettingsService } from './system-settings.service';

// N8N API configuration
interface N8NConfig {
  baseUrl: string;
  apiKey: string;
}

// Provisioning options
interface ProvisioningOptions {
  userId: string;
  tier?: string;
  enableWhatsApp?: boolean;
  enableVoiceAgent?: boolean;
  enableN8NWorkflow?: boolean;
  whatsappPhoneNumber?: string;
  customWorkflowConfig?: Record<string, unknown>;
}

// Provisioning result
interface ProvisioningResult {
  success: boolean;
  userId: string;
  webhookToken?: string;
  n8nWorkflowId?: string;
  n8nWebhookUrl?: string;
  whatsappConfigured: boolean;
  voiceAgentConfigured: boolean;
  workflowsCreated: string[];
  errors: string[];
  webhookEndpoints: {
    conversation: string;
    booking: string;
    lead: string;
    context: string;
  };
}

// N8N Workflow template
interface N8NWorkflowTemplate {
  name: string;
  nodes: unknown[];
  connections: Record<string, unknown>;
  settings: Record<string, unknown>;
  tags?: { name: string }[];
}

/**
 * N8N API Client for workflow management
 */
class N8NApiClient {
  private baseUrl: string;
  private apiKey: string;

  constructor(config: N8NConfig) {
    this.baseUrl = config.baseUrl.replace(/\/$/, '');
    this.apiKey = config.apiKey;
  }

  private async request<T>(
    endpoint: string,
    method: string = 'GET',
    body?: unknown
  ): Promise<T> {
    const response = await fetch(`${this.baseUrl}/api/v1${endpoint}`, {
      method,
      headers: {
        'X-N8N-API-KEY': this.apiKey,
        'Content-Type': 'application/json',
      },
      body: body ? JSON.stringify(body) : undefined,
    });

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`N8N API Error: ${response.status} - ${errorText}`);
    }

    return response.json();
  }

  /**
   * Create a new workflow in N8N
   */
  async createWorkflow(workflow: N8NWorkflowTemplate): Promise<{
    id: string;
    name: string;
    active: boolean;
  }> {
    return this.request('/workflows', 'POST', workflow);
  }

  /**
   * Activate a workflow
   */
  async activateWorkflow(workflowId: string): Promise<void> {
    await this.request(`/workflows/${workflowId}/activate`, 'POST');
  }

  /**
   * Get workflow details including webhook URL
   */
  async getWorkflow(workflowId: string): Promise<{
    id: string;
    name: string;
    active: boolean;
    nodes: Array<{
      type: string;
      webhookId?: string;
      parameters?: { path?: string };
    }>;
  }> {
    return this.request(`/workflows/${workflowId}`);
  }

  /**
   * Delete a workflow
   */
  async deleteWorkflow(workflowId: string): Promise<void> {
    await this.request(`/workflows/${workflowId}`, 'DELETE');
  }

  /**
   * Test connection to N8N
   */
  async testConnection(): Promise<boolean> {
    try {
      await this.request('/workflows?limit=1');
      return true;
    } catch {
      return false;
    }
  }
}

/**
 * Generate a unique webhook token for a user
 */
function generateWebhookToken(): string {
  const timestamp = Date.now().toString(36);
  const random = randomBytes(32).toString('hex');
  return `mawidi_${timestamp}_${random}`;
}

/**
 * Generate a short unique identifier for workflow naming
 */
function generateShortId(): string {
  return randomBytes(4).toString('hex');
}

/**
 * Create N8N workflow template for a specific user
 */
function createUserWorkflowTemplate(
  userId: string,
  userName: string,
  webhookToken: string,
  mawimiApiUrl: string
): N8NWorkflowTemplate {
  const shortId = generateShortId();
  const webhookPath = `mawidi-${userId.substring(0, 8)}-${shortId}`;

  return {
    name: `Mawidi AI Agent - ${userName} (${shortId})`,
    nodes: [
      {
        parameters: {
          httpMethod: 'POST',
          path: webhookPath,
          responseMode: 'responseNode',
          options: {},
        },
        id: `webhook-${shortId}`,
        name: 'WhatsApp Webhook',
        type: 'n8n-nodes-base.webhook',
        typeVersion: 2,
        position: [200, 300],
        webhookId: `mawidi-webhook-${shortId}`,
      },
      {
        parameters: {
          method: 'POST',
          url: `${mawimiApiUrl}/api/n8n/context`,
          sendHeaders: true,
          headerParameters: {
            parameters: [
              { name: 'Content-Type', value: 'application/json' },
              { name: 'Authorization', value: `Bearer ${webhookToken}` },
            ],
          },
          sendBody: true,
          specifyBody: 'json',
          jsonBody: JSON.stringify({
            auth_token: webhookToken,
            lookup_type: 'webhook_token',
            lookup_value: webhookToken,
            include: {
              knowledge_base: true,
              credentials: true,
              workflow_config: true,
              recent_conversations: true,
            },
          }),
          options: {},
        },
        id: `context-${shortId}`,
        name: 'Get User Context',
        type: 'n8n-nodes-base.httpRequest',
        typeVersion: 4.2,
        position: [450, 300],
      },
      {
        parameters: {
          conditions: {
            boolean: [
              {
                value1: '={{$json.success}}',
                value2: true,
              },
            ],
          },
        },
        id: `check-${shortId}`,
        name: 'User Found?',
        type: 'n8n-nodes-base.if',
        typeVersion: 2,
        position: [700, 300],
      },
      {
        parameters: {
          resource: 'chat',
          operation: 'message',
          modelId: {
            __rl: true,
            value: 'gpt-4o-mini',
            mode: 'list',
          },
          messages: {
            values: [
              {
                content: `You are an AI assistant for {{$node['Get User Context'].json.user.company_name || 'a business'}}.

Language: Respond in {{$node['Get User Context'].json.user.language === 'ar' ? 'Arabic' : 'English'}}.

Custom Instructions:
{{$node['Get User Context'].json.knowledge_base.custom_instructions || 'Be helpful and professional.'}}

FAQ Knowledge:
{{$node['Get User Context'].json.knowledge_base.faq_summary.map(f => \`Q: \${f.question}\\nA: \${f.answer}\`).join('\\n\\n') || 'No FAQ available.'}}

Recent conversation context:
{{$node['Get User Context'].json.recent_conversations?.map(c => c.last_message).join('\\n') || 'No recent messages.'}}`,
              },
              {
                content: "={{$node['WhatsApp Webhook'].json.body.message}}",
                role: 'user',
              },
            ],
          },
          options: {
            maxTokens: 500,
            temperature: 0.7,
          },
        },
        id: `ai-${shortId}`,
        name: 'Generate AI Response',
        type: '@n8n/n8n-nodes-langchain.openAi',
        typeVersion: 1.4,
        position: [950, 200],
        credentials: {
          openAiApi: {
            id: 'openai-creds',
            name: 'OpenAI Account',
          },
        },
      },
      {
        parameters: {
          method: 'POST',
          url: `${mawimiApiUrl}/api/webhooks/n8n/conversation`,
          sendHeaders: true,
          headerParameters: {
            parameters: [
              { name: 'Content-Type', value: 'application/json' },
              { name: 'Authorization', value: `Bearer ${webhookToken}` },
            ],
          },
          sendBody: true,
          specifyBody: 'json',
          jsonBody: `{
  "auth_token": "${webhookToken}",
  "user_id": "{{$node['Get User Context'].json.user.id}}",
  "platform": "whatsapp",
  "customer_phone": "{{$node['WhatsApp Webhook'].json.body.from}}",
  "customer_name": "{{$node['WhatsApp Webhook'].json.body.customer_name || 'Unknown'}}",
  "message": {
    "role": "user",
    "content": "{{$node['WhatsApp Webhook'].json.body.message}}",
    "timestamp": "{{$now.toISO()}}"
  }
}`,
          options: {},
        },
        id: `log-user-${shortId}`,
        name: 'Log User Message',
        type: 'n8n-nodes-base.httpRequest',
        typeVersion: 4.2,
        position: [950, 350],
      },
      {
        parameters: {
          method: 'POST',
          url: `${mawimiApiUrl}/api/webhooks/n8n/conversation`,
          sendHeaders: true,
          headerParameters: {
            parameters: [
              { name: 'Content-Type', value: 'application/json' },
              { name: 'Authorization', value: `Bearer ${webhookToken}` },
            ],
          },
          sendBody: true,
          specifyBody: 'json',
          jsonBody: `{
  "auth_token": "${webhookToken}",
  "user_id": "{{$node['Get User Context'].json.user.id}}",
  "conversation_id": "{{$node['Log User Message'].json.conversation_id}}",
  "platform": "whatsapp",
  "customer_phone": "{{$node['WhatsApp Webhook'].json.body.from}}",
  "message": {
    "role": "agent",
    "content": "{{$node['Generate AI Response'].json.message.content}}",
    "timestamp": "{{$now.toISO()}}"
  }
}`,
          options: {},
        },
        id: `log-agent-${shortId}`,
        name: 'Log Agent Response',
        type: 'n8n-nodes-base.httpRequest',
        typeVersion: 4.2,
        position: [1200, 200],
      },
      {
        parameters: {
          respondWith: 'json',
          responseBody:
            "={{ { success: true, response: $node['Generate AI Response'].json.message.content, conversation_id: $node['Log User Message'].json.conversation_id } }}",
          options: {},
        },
        id: `respond-ok-${shortId}`,
        name: 'Respond Success',
        type: 'n8n-nodes-base.respondToWebhook',
        typeVersion: 1.1,
        position: [1450, 200],
      },
      {
        parameters: {
          respondWith: 'json',
          responseBody: "={{ { success: false, error: 'User not found or inactive' } }}",
          options: { responseCode: 404 },
        },
        id: `respond-err-${shortId}`,
        name: 'Respond Not Found',
        type: 'n8n-nodes-base.respondToWebhook',
        typeVersion: 1.1,
        position: [950, 450],
      },
    ],
    connections: {
      'WhatsApp Webhook': {
        main: [[{ node: 'Get User Context', type: 'main', index: 0 }]],
      },
      'Get User Context': {
        main: [[{ node: 'User Found?', type: 'main', index: 0 }]],
      },
      'User Found?': {
        main: [
          [
            { node: 'Generate AI Response', type: 'main', index: 0 },
            { node: 'Log User Message', type: 'main', index: 0 },
          ],
          [{ node: 'Respond Not Found', type: 'main', index: 0 }],
        ],
      },
      'Generate AI Response': {
        main: [[{ node: 'Log Agent Response', type: 'main', index: 0 }]],
      },
      'Log Agent Response': {
        main: [[{ node: 'Respond Success', type: 'main', index: 0 }]],
      },
    },
    settings: {
      executionOrder: 'v1',
    },
    tags: [
      { name: 'mawidi' },
      { name: 'auto-provisioned' },
      { name: `user-${userId.substring(0, 8)}` },
    ],
  };
}

/**
 * Webhook Provisioning Service
 */
export class WebhookProvisioningService {
  private n8nClient: N8NApiClient | null = null;

  /**
   * Initialize N8N client with credentials
   */
  private async getN8NClient(): Promise<N8NApiClient | null> {
    if (this.n8nClient) {
      return this.n8nClient;
    }

    try {
      // Get N8N configuration from system settings or environment
      const baseUrl =
        (await systemSettingsService.getSetting('n8n.base_url')) ||
        process.env.N8N_BASE_URL ||
        process.env.N8N_WEBHOOK_URL;

      const apiKey =
        (await systemSettingsService.getSetting('n8n.api_key')) ||
        process.env.N8N_API_KEY;

      if (!baseUrl || !apiKey) {
        console.warn('[WebhookProvisioning] N8N configuration not found');
        return null;
      }

      this.n8nClient = new N8NApiClient({ baseUrl, apiKey });

      // Test connection
      const connected = await this.n8nClient.testConnection();
      if (!connected) {
        console.error('[WebhookProvisioning] Failed to connect to N8N');
        this.n8nClient = null;
        return null;
      }

      return this.n8nClient;
    } catch (error) {
      console.error('[WebhookProvisioning] Error initializing N8N client:', error);
      return null;
    }
  }

  /**
   * Provision all webhooks for a user
   */
  async provisionUser(options: ProvisioningOptions): Promise<ProvisioningResult> {
    const {
      userId,
      tier = 'tier1',
      enableWhatsApp = true,
      enableVoiceAgent = false,
      enableN8NWorkflow = true,
    } = options;

    const result: ProvisioningResult = {
      success: false,
      userId,
      whatsappConfigured: false,
      voiceAgentConfigured: false,
      workflowsCreated: [],
      errors: [],
      webhookEndpoints: {
        conversation: `${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:9000'}/api/webhooks/n8n/conversation`,
        booking: `${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:9000'}/api/webhooks/n8n/booking`,
        lead: `${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:9000'}/api/webhooks/n8n/lead`,
        context: `${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:9000'}/api/n8n/context`,
      },
    };

    try {
      // 1. Get user information
      const user = await prisma.users.findUnique({
        where: { id: userId },
        select: {
          id: true,
          name: true,
          email: true,
          n8nWebhookToken: true,
          n8nWorkflowId: true,
          whatsappConnected: true,
          voiceAgentId: true,
        },
      });

      if (!user) {
        result.errors.push('User not found');
        return result;
      }

      // 2. Generate webhook token if not exists
      let webhookToken = user.n8nWebhookToken;
      if (!webhookToken) {
        webhookToken = generateWebhookToken();

        console.log(`[WebhookProvisioning] Generated token for user ${userId}`);
      }
      result.webhookToken = webhookToken;

      // 3. Deploy N8N workflow if enabled
      if (enableN8NWorkflow) {
        const n8nClient = await this.getN8NClient();

        if (n8nClient) {
          try {
            const mawimiApiUrl =
              process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:9000';

            // Create workflow template
            const workflowTemplate = createUserWorkflowTemplate(
              userId,
              user.name || 'User',
              webhookToken,
              mawimiApiUrl
            );

            // Deploy to N8N
            const createdWorkflow = await n8nClient.createWorkflow(workflowTemplate);
            result.n8nWorkflowId = createdWorkflow.id;

            // Activate workflow
            await n8nClient.activateWorkflow(createdWorkflow.id);

            // Get webhook URL
            const workflowDetails = await n8nClient.getWorkflow(createdWorkflow.id);
            const webhookNode = workflowDetails.nodes.find(
              (n) => n.type === 'n8n-nodes-base.webhook'
            );

            if (webhookNode?.parameters?.path) {
              const n8nBaseUrl =
                (await systemSettingsService.getSetting('n8n.base_url')) ||
                process.env.N8N_WEBHOOK_URL ||
                '';
              result.n8nWebhookUrl = `${n8nBaseUrl}/webhook/${webhookNode.parameters.path}`;
            }

            // Update user with workflow info

            // Create workflow record in database
            await this.createWorkflowRecord(userId, 'ai_agent', createdWorkflow.id);
            result.workflowsCreated.push('ai_agent');

            console.log(
              `[WebhookProvisioning] Deployed N8N workflow ${createdWorkflow.id} for user ${userId}`
            );
          } catch (n8nError) {
            const errorMsg =
              n8nError instanceof Error ? n8nError.message : 'Unknown N8N error';
            result.errors.push(`N8N workflow deployment failed: ${errorMsg}`);
            console.error('[WebhookProvisioning] N8N deployment error:', n8nError);
          }
        } else {
          result.errors.push(
            'N8N client not available - workflow deployment skipped'
          );
        }
      }

      // 4. Configure WhatsApp routing if enabled
      if (enableWhatsApp && options.whatsappPhoneNumber) {
        try {
          result.whatsappConfigured = true;

          // Create WhatsApp workflow record
          await this.createWorkflowRecord(userId, 'whatsapp', null);
          result.workflowsCreated.push('whatsapp');

          console.log(
            `[WebhookProvisioning] Configured WhatsApp for user ${userId}`
          );
        } catch (whatsappError) {
          const errorMsg =
            whatsappError instanceof Error
              ? whatsappError.message
              : 'Unknown WhatsApp error';
          result.errors.push(`WhatsApp configuration failed: ${errorMsg}`);
        }
      }

      // 5. Initialize voice agent placeholder if enabled
      if (enableVoiceAgent) {
        try {
          // Create voice agent workflow record (actual provisioning via separate API)
          await this.createWorkflowRecord(userId, 'voice_agent', null, {
            status: 'pending_setup',
          });
          result.workflowsCreated.push('voice_agent');
          result.voiceAgentConfigured = true;

          console.log(
            `[WebhookProvisioning] Initialized voice agent for user ${userId}`
          );
        } catch (voiceError) {
          const errorMsg =
            voiceError instanceof Error
              ? voiceError.message
              : 'Unknown voice agent error';
          result.errors.push(`Voice agent initialization failed: ${errorMsg}`);
        }
      }

      // 6. Create additional workflow records based on tier
      const tierWorkflows = this.getTierWorkflows(tier);
      for (const workflowType of tierWorkflows) {
        if (!result.workflowsCreated.includes(workflowType)) {
          try {
            await this.createWorkflowRecord(userId, workflowType, null, {
              status: 'inactive',
            });
            result.workflowsCreated.push(workflowType);
          } catch {
            // Workflow may already exist - that's fine
          }
        }
      }

      // 7. Update onboarding progress
      await this.updateOnboardingProgress(userId, 'workflows');

      result.success = result.errors.length === 0;
      return result;
    } catch (error) {
      const errorMsg =
        error instanceof Error ? error.message : 'Unknown provisioning error';
      result.errors.push(errorMsg);
      console.error('[WebhookProvisioning] Provisioning failed:', error);
      return result;
    }
  }

  /**
   * Deprovision webhooks for a user (cleanup)
   */
  async deprovisionUser(userId: string): Promise<{ success: boolean; errors: string[] }> {
    const errors: string[] = [];

    try {
      // Get user's N8N workflow ID
      const user = await prisma.users.findUnique({
        where: { id: userId },
        select: { n8nWorkflowId: true },
      });

      // Delete N8N workflow if exists
      if (user?.n8nWorkflowId) {
        const n8nClient = await this.getN8NClient();
        if (n8nClient) {
          try {
            await n8nClient.deleteWorkflow(user.n8nWorkflowId);
            console.log(
              `[WebhookProvisioning] Deleted N8N workflow ${user.n8nWorkflowId}`
            );
          } catch (n8nError) {
            errors.push(`Failed to delete N8N workflow: ${n8nError}`);
          }
        }
      }

      // Clear user webhook configuration

      // Delete workflow records
      await prisma.userWorkflow.deleteMany({
        where: { userId },
      });

      console.log(`[WebhookProvisioning] Deprovisioned user ${userId}`);

      return { success: errors.length === 0, errors };
    } catch (error) {
      const errorMsg =
        error instanceof Error ? error.message : 'Unknown deprovisioning error';
      errors.push(errorMsg);
      return { success: false, errors };
    }
  }

  /**
   * Get provisioning status for a user
   */
  async getProvisioningStatus(userId: string): Promise<{
    webhookToken: boolean;
    n8nWorkflow: boolean;
    n8nWorkflowActive: boolean;
    whatsappConnected: boolean;
    voiceAgentConfigured: boolean;
    workflowCount: number;
    activeWorkflowCount: number;
  }> {
    const user = await prisma.users.findUnique({
      where: { id: userId },
      select: {
        n8nWebhookToken: true,
        n8nWorkflowId: true,
        whatsappConnected: true,
        voiceAgentId: true,
      },
    });

    const workflows = await prisma.userWorkflow.findMany({
      where: { userId },
      select: { status: true },
    });

    // Check N8N workflow status
    let n8nWorkflowActive = false;
    if (user?.n8nWorkflowId) {
      const n8nClient = await this.getN8NClient();
      if (n8nClient) {
        try {
          const workflow = await n8nClient.getWorkflow(user.n8nWorkflowId);
          n8nWorkflowActive = workflow.active;
        } catch {
          // Workflow may not exist anymore
        }
      }
    }

    return {
      webhookToken: !!user?.n8nWebhookToken,
      n8nWorkflow: !!user?.n8nWorkflowId,
      n8nWorkflowActive,
      whatsappConnected: user?.whatsappConnected || false,
      voiceAgentConfigured: !!user?.voiceAgentId,
      workflowCount: workflows.length,
      activeWorkflowCount: workflows.filter((w) => w.status === 'active').length,
    };
  }

  /**
   * Regenerate webhook token for a user
   */
  async regenerateWebhookToken(userId: string): Promise<string> {
    const newToken = generateWebhookToken();

    console.log(`[WebhookProvisioning] Regenerated token for user ${userId}`);

    return newToken;
  }

  /**
   * Create a workflow record in the database
   */
  private async createWorkflowRecord(
    userId: string,
    workflowType: string,
    n8nWorkflowId: string | null,
    config: Record<string, unknown> = {}
  ): Promise<void> {
    // Check if workflow already exists
    const existing = await prisma.userWorkflow.findFirst({
      where: { userId, workflowType },
    });

    if (existing) {
      // Update existing
    } else {
      // Create new
    }
  }

  /**
   * Get workflow types available for a tier
   */
  private getTierWorkflows(tier: string): string[] {
    const tierMap: Record<string, string[]> = {
      tier1: ['ai_agent', 'whatsapp', 'appointments'],
      tier2: [
        'ai_agent',
        'whatsapp',
        'appointments',
        'quotations',
        'crm',
        'integrations',
        'deposits',
      ],
      tier3: [
        'ai_agent',
        'whatsapp',
        'appointments',
        'quotations',
        'crm',
        'integrations',
        'deposits',
        'voice_agent',
        'multi_staff',
        'recurring',
      ],
      tier4: [
        'ai_agent',
        'whatsapp',
        'appointments',
        'quotations',
        'crm',
        'integrations',
        'deposits',
        'voice_agent',
        'multi_staff',
        'recurring',
        'social_media',
        'ai_social',
      ],
      tier5: [
        'ai_agent',
        'whatsapp',
        'appointments',
        'quotations',
        'crm',
        'integrations',
        'deposits',
        'voice_agent',
        'multi_staff',
        'recurring',
        'social_media',
        'ai_social',
        'lead_generation',
        'lead_scoring',
      ],
    };

    return tierMap[tier] || tierMap.tier1;
  }

  /**
   * Update onboarding progress
   */
  private async updateOnboardingProgress(
    userId: string,
    step: string
  ): Promise<void> {
    try {
      const existing = await prisma.onboarding_progress.findUnique({
        where: { userId },
      });

      if (existing) {
        await prisma.onboarding_progress.update({
          where: { userId },
          data: {
            [step]: 'completed',
            updatedAt: new Date(),
          },
        });
      }
    } catch {
      // Onboarding progress may not exist yet - that's fine
    }
  }
}

// Export singleton instance
export const webhookProvisioningService = new WebhookProvisioningService();
