/**
 * Organization WhatsApp Keys Service
 *
 * Manages organization-specific WhatsApp Business API keys with encryption.
 * Provides masked values for UI display and helpers for webhook verification.
 */

import crypto from 'crypto';
import { encrypt, decrypt } from '@/lib/encryption';
import { logger } from '@/lib/logger';
import { fetchWithTimeout } from '@/lib/fetch-with-timeout';
import { organizationsAdapter } from '@/lib/adapters/organizations';

export interface WhatsAppKeysConfig {
  phoneNumberId: string;
  accessToken: string;
  appSecret: string;
  displayNumber?: string;
}

export interface MaskedWhatsAppKeysConfig {
  phoneNumberId: string;
  accessTokenMasked: string;
  appSecretMasked: string;
  displayNumber?: string;
  verifyToken?: string;
  webhookUrl?: string;
  configuredAt: Date | null;
  configuredBy: string | null;
  webhookVerified: boolean;
}

export interface WhatsAppKeyValidationResult {
  valid: boolean;
  error?: string;
  displayNumber?: string;
  businessName?: string;
}

export interface DecryptedWhatsAppCredentials {
  phoneNumberId: string;
  accessToken: string;
  appSecret: string;
  displayNumber?: string | null;
}

class OrgWhatsAppKeysService {
  private maskKey(value: string): string {
    if (!value) return '';
    const visible = 4;
    if (value.length <= visible * 2) {
      return `${value.substring(0, 1)}***${value.substring(value.length - 1)}`;
    }
    return `${value.substring(0, visible)}***${value.substring(value.length - visible)}`;
  }

  private buildWebhookUrl(): string | undefined {
    const baseUrl = process.env.NEXT_PUBLIC_APP_URL || process.env.NEXTAUTH_URL;
    if (!baseUrl) return undefined;
    return `${baseUrl.replace(/\/$/, '')}/api/webhooks/whatsapp`;
  }

  async getMaskedKeys(organizationId: string): Promise<MaskedWhatsAppKeysConfig | null> {
    try {
      const org = await organizationsAdapter.findUnique({
        where: { id: organizationId },
        select: {
          whatsappPhoneNumberId: true,
          whatsappAccessTokenEncrypted: true,
          whatsappAppSecretEncrypted: true,
          whatsappDisplayNumber: true,
          whatsappVerifyToken: true,
          whatsappWebhookVerified: true,
          whatsappConfiguredAt: true,
          whatsappConfiguredBy: true,
        },
      }) as Record<string, unknown> | null;

      if (!org || !org.whatsappPhoneNumberId || !org.whatsappAccessTokenEncrypted || !org.whatsappAppSecretEncrypted) {
        return null;
      }

      return {
        phoneNumberId: org.whatsappPhoneNumberId as string,
        accessTokenMasked: this.maskKey(org.whatsappAccessTokenEncrypted as string),
        appSecretMasked: this.maskKey(org.whatsappAppSecretEncrypted as string),
        displayNumber: (org.whatsappDisplayNumber as string) ?? undefined,
        verifyToken: (org.whatsappVerifyToken as string) ?? undefined,
        webhookUrl: this.buildWebhookUrl(),
        configuredAt: org.whatsappConfiguredAt as Date | null,
        configuredBy: org.whatsappConfiguredBy as string | null,
        webhookVerified: (org.whatsappWebhookVerified as boolean) ?? false,
      };
    } catch (error) {
      logger.error('Failed to get masked WhatsApp keys', { organizationId, error });
      return null;
    }
  }

  async validateKeys(phoneNumberId: string, accessToken: string): Promise<WhatsAppKeyValidationResult> {
    try {
      const url = `https://graph.facebook.com/v19.0/${phoneNumberId}?fields=display_phone_number,verified_name&access_token=${accessToken}`;
      const response = await fetchWithTimeout(url, { method: 'GET' }, 8000);

      const data = await response.json();

      // Check for Meta API error in response body
      if (data.error) {
        const errorMessage = data.error.message || 'Invalid WhatsApp credentials';
        const errorCode = data.error.code;

        // Provide user-friendly error messages for common errors
        let friendlyError = errorMessage;
        if (errorCode === 190 || errorMessage.includes('Invalid OAuth')) {
          friendlyError = 'Invalid or expired access token. Please generate a new token from Meta Developer Console.';
        } else if (errorCode === 100 || errorMessage.includes('does not exist')) {
          friendlyError = 'Phone Number ID not found. Please verify the ID in your WhatsApp Business Settings.';
        } else if (errorCode === 10 || errorMessage.includes('permission')) {
          friendlyError = 'Access token lacks required permissions. Ensure the token has whatsapp_business_messaging permission.';
        }

        logger.warn('Meta API validation error', {
          errorCode,
          errorMessage,
          phoneNumberId: phoneNumberId.substring(0, 4) + '***'
        });

        return {
          valid: false,
          error: friendlyError,
        };
      }

      if (!response.ok) {
        return {
          valid: false,
          error: `Meta API returned status ${response.status}. Please check your credentials.`,
        };
      }

      return {
        valid: true,
        displayNumber: data.display_phone_number,
        businessName: data.verified_name,
      };
    } catch (error) {
      logger.error('WhatsApp key validation failed', { error });

      // Handle network/timeout errors
      if (error instanceof Error) {
        if (error.message.includes('timeout') || error.message.includes('Timeout')) {
          return {
            valid: false,
            error: 'Connection to Meta API timed out. Please try again.',
          };
        }
        if (error.message.includes('fetch') || error.message.includes('network')) {
          return {
            valid: false,
            error: 'Unable to connect to Meta API. Please check your internet connection.',
          };
        }
      }

      return {
        valid: false,
        error: error instanceof Error ? error.message : 'Validation failed. Please try again.',
      };
    }
  }

  async saveKeys(
    organizationId: string,
    keys: WhatsAppKeysConfig,
    staffId: string
  ): Promise<boolean> {
    try {
      const encryptedAccessToken = encrypt(keys.accessToken);
      const encryptedAppSecret = encrypt(keys.appSecret);

      const existing = await organizationsAdapter.findUnique({
        where: { id: organizationId },
        select: { whatsappVerifyToken: true },
      });

      const verifyToken = existing?.whatsappVerifyToken || crypto.randomUUID();

      await organizationsAdapter.update({
        where: { id: organizationId },
        data: {
          whatsappPhoneNumberId: keys.phoneNumberId,
          whatsappAccessTokenEncrypted: encryptedAccessToken,
          whatsappAppSecretEncrypted: encryptedAppSecret,
          whatsappDisplayNumber: keys.displayNumber ?? null,
          whatsappVerifyToken: verifyToken,
          whatsappWebhookVerified: false,
          whatsappConfiguredAt: new Date(),
          whatsappConfiguredBy: staffId,
          // Track issuance time so meta-token-refresh.service.ts can rotate
          // the long-lived token before the ~60-day Meta expiry.
          whatsappTokenIssuedAt: Date.now(),
          updatedAt: new Date(),
        },
      });

      logger.info('WhatsApp keys saved successfully', { organizationId, staffId });
      return true;
    } catch (error) {
      logger.error('Failed to save WhatsApp keys', { organizationId, staffId, error });
      return false;
    }
  }

  async deleteKeys(organizationId: string, staffId: string): Promise<boolean> {
    try {
      await organizationsAdapter.update({
        where: { id: organizationId },
        data: {
          whatsappPhoneNumberId: null,
          whatsappAccessTokenEncrypted: null,
          whatsappAppSecretEncrypted: null,
          whatsappDisplayNumber: null,
          whatsappVerifyToken: null,
          whatsappWebhookVerified: false,
          whatsappConfiguredAt: null,
          whatsappConfiguredBy: null,
          updatedAt: new Date(),
        },
      });

      logger.info('WhatsApp keys deleted', { organizationId, staffId });
      return true;
    } catch (error) {
      logger.error('Failed to delete WhatsApp keys', { organizationId, staffId, error });
      return false;
    }
  }

  async getOrgByVerifyToken(token: string): Promise<{ id: string; name: string; ownerId: string } | null> {
    const org = await organizationsAdapter.findFirst({
      where: { whatsappVerifyToken: token },
    }) as Record<string, unknown> | null;
    if (!org) return null;
    return { id: org.id as string, name: org.name as string, ownerId: org.ownerId as string };
  }

  async markWebhookVerified(organizationId: string): Promise<void> {
    await organizationsAdapter.update({
      where: { id: organizationId },
      data: {
        whatsappWebhookVerified: true,
        updatedAt: new Date(),
      },
    });
  }

  async getOrgByPhoneNumberId(phoneNumberId: string): Promise<{ id: string; name: string; ownerId: string } | null> {
    const org = await organizationsAdapter.findFirst({
      where: { whatsappPhoneNumberId: phoneNumberId },
    }) as Record<string, unknown> | null;
    if (!org) return null;
    return { id: org.id as string, name: org.name as string, ownerId: org.ownerId as string };
  }

  async getDecryptedCredentials(organizationId: string): Promise<DecryptedWhatsAppCredentials | null> {
    try {
      const org = await organizationsAdapter.findUnique({
        where: { id: organizationId },
        select: {
          whatsappPhoneNumberId: true,
          whatsappAccessTokenEncrypted: true,
          whatsappAppSecretEncrypted: true,
          whatsappDisplayNumber: true,
        },
      }) as Record<string, unknown> | null;

      if (!org || !org.whatsappPhoneNumberId || !org.whatsappAccessTokenEncrypted || !org.whatsappAppSecretEncrypted) {
        return null;
      }

      return {
        phoneNumberId: org.whatsappPhoneNumberId as string,
        accessToken: decrypt(org.whatsappAccessTokenEncrypted as string),
        appSecret: decrypt(org.whatsappAppSecretEncrypted as string),
        displayNumber: org.whatsappDisplayNumber as string | null | undefined,
      };
    } catch (error) {
      logger.error('Failed to decrypt WhatsApp credentials', { organizationId, error });
      return null;
    }
  }
}

export const orgWhatsAppKeysService = new OrgWhatsAppKeysService();
