import { supabase } from "@/integrations/supabase/client";
import { invokeWithTracking } from "@/lib/edgeFunctionTracking";
import { logger } from "@/lib/logger";
import { AppError } from "@/lib/errorHandler";
import { z } from "zod";
import type {
  NotificationPayload,
  SubscriberData,
  NotificationPreferences,
  NotificationTemplate
} from "@/types/notifications";
import {
  notificationPreferencesSchema,
  subscriberDataSchema,
  DEFAULT_NOTIFICATION_PREFERENCES
} from "@/lib/notificationValidation";

class NotificationService {
  /**
   * Check if Novu is enabled by checking admin settings
   */
  async isNovuEnabled(): Promise<boolean> {
    try {
      const { data } = await supabase
        .from('admin_settings')
        .select('setting_value')
        .eq('setting_key', 'novu.application_identifier')
        .maybeSingle();
      
      return !!data?.setting_value;
    } catch (error: unknown) {
      logger.error('Failed to check Novu status', {
        action: 'check_novu_status',
        error: error instanceof Error ? error.message : String(error)
      });
      return false;
    }
  }

  /**
   * Update an existing Novu subscriber's profile information
   */
  async updateSubscriber(subscriberData: SubscriberData): Promise<{ success: boolean; error?: string }> {
    try {
      // Validate input
      const validated = subscriberDataSchema.parse(subscriberData);
      
      const novuEnabled = await this.isNovuEnabled();
      if (!novuEnabled) {
        logger.warn('Novu not configured, skipping subscriber update', {
          action: 'update_novu_subscriber',
          userId: validated.subscriberId
        });
        return { success: false, error: 'Novu not configured' };
      }

      const { data, error, requestId } = await invokeWithTracking(
        'update-novu-subscriber',
        validated
      );

      if (error) {
        logger.error('Edge function error updating Novu subscriber', {
          action: 'update_novu_subscriber',
          userId: validated.subscriberId,
          requestId,
          error: error.message
        });
        throw new AppError(
          'Failed to update notification subscriber',
          'NOTIFICATION_ERROR',
          error.message
        );
      }

      logger.info('Novu subscriber updated successfully', {
        action: 'update_novu_subscriber',
        userId: validated.subscriberId,
        requestId
      });

      return { success: true };
    } catch (error: unknown) {
      logger.error('Error in updateSubscriber', {
        action: 'update_novu_subscriber',
        userId: subscriberData.subscriberId,
        error: error instanceof Error ? error.message : String(error)
      });

      return {
        success: false,
        error: error instanceof AppError ? error.message : 'Failed to update subscriber'
      };
    }
  }

  /**
   * Create or update a Novu subscriber
   */
  async createSubscriber(subscriberData: SubscriberData): Promise<{ success: boolean; error?: string }> {
    try {
      // Validate input
      const validated = subscriberDataSchema.parse(subscriberData);
      
      const novuEnabled = await this.isNovuEnabled();
      if (!novuEnabled) {
        logger.warn('Novu not configured, skipping subscriber creation', {
          action: 'create_novu_subscriber',
          userId: validated.subscriberId
        });
        return { success: false, error: 'Novu not configured' };
      }

      const { data, error, requestId } = await invokeWithTracking(
        'create-novu-subscriber',
        validated
      );

      if (error) {
        logger.error('Edge function error creating Novu subscriber', {
          action: 'create_novu_subscriber',
          userId: validated.subscriberId,
          requestId,
          error: error.message
        });
        throw new AppError(
          'Failed to create notification subscriber',
          'NOTIFICATION_ERROR',
          error.message
        );
      }

      if (!data?.subscriberId) {
        throw new AppError(
          'Invalid response from notification service',
          'NOTIFICATION_ERROR'
        );
      }

      // Store subscriber ID in database
      const { error: dbError } = await supabase
        .from('user_notification_preferences')
        .upsert({
          user_id: validated.subscriberId,
          novu_subscriber_id: data.subscriberId,
        });

      if (dbError) {
        logger.error('Failed to store subscriber preferences', {
          action: 'store_subscriber_preferences',
          userId: validated.subscriberId,
          error: dbError.message,
          errorCode: dbError.code
        });
        throw dbError;
      }

      logger.info('Novu subscriber created successfully', {
        action: 'create_novu_subscriber',
        userId: validated.subscriberId,
        requestId
      });

      return { success: true };
    } catch (error: unknown) {
      logger.error('Error in createSubscriber', {
        action: 'create_novu_subscriber',
        userId: subscriberData.subscriberId,
        error: error instanceof Error ? error.message : String(error)
      });

      return {
        success: false,
        error: error instanceof AppError ? error.message : 'Failed to create subscriber'
      };
    }
  }

  /**
   * Update notification preferences with validation and audit logging
   */
  async updatePreferences(
    userId: string,
    preferences: NotificationPreferences
  ): Promise<{ success: boolean; error?: string }> {
    try {
      // Validate preferences
      const validated = notificationPreferencesSchema.parse(preferences);

      // Get previous preferences for audit log
      const { data: previousPrefs } = await supabase
        .from('user_notification_preferences')
        .select('channel_preferences, workflow_preferences, frequency_settings')
        .eq('user_id', userId)
        .maybeSingle();

      const novuEnabled = await this.isNovuEnabled();

      // Update Novu preferences if enabled
      if (novuEnabled) {
        const { error: novuError, requestId } = await invokeWithTracking(
          'update-novu-preferences',
          {
            userId,
            preferences: validated,
          }
        );

        if (novuError) {
          logger.error('Failed to update Novu preferences', {
            action: 'update_novu_preferences',
            userId,
            requestId,
            error: novuError.message
          });
          throw novuError;
        }
      }

      // Update local database
      const { error: dbError } = await supabase
        .from('user_notification_preferences')
        .upsert({
          user_id: userId,
          channel_preferences: validated.channelPreferences,
          workflow_preferences: validated.workflowPreferences,
          frequency_settings: validated.frequencySettings,
        });

      if (dbError) {
        logger.error('Failed to save notification preferences', {
          action: 'save_notification_preferences',
          userId,
          error: dbError.message,
          errorCode: dbError.code
        });
        throw dbError;
      }

      // Create audit log entry
      // DOCUMENTED EXCEPTION: profile_audit_log.changes column accepts JSONB
      // We validate the preferences structure with Zod before this point
      // Safe because the payload is constructed type-safely earlier in the function
      await supabase.from('profile_audit_log').insert([{
        user_id: userId,
        changed_by: userId,
        action: 'notification_preferences_updated',
        changes: {
          previous: previousPrefs || null,
          updated: validated,
          timestamp: new Date().toISOString()
        }
      }]);

      logger.info('Notification preferences updated', {
        action: 'update_notification_preferences',
        userId
      });

      return { success: true };
    } catch (error: unknown) {
      logger.error('Error updating notification preferences', {
        action: 'update_notification_preferences',
        userId,
        error: error instanceof Error ? error.message : String(error)
      });

      if (error instanceof z.ZodError) {
        return {
          success: false,
          error: `Invalid preferences: ${error.issues.map(i => i.message).join(', ')}`
        };
      }

      return {
        success: false,
        error: 'Failed to update notification preferences'
      };
    }
  }

  /**
   * Get user's notification preferences with proper typing
   */
  async getPreferences(userId: string): Promise<NotificationPreferences | null> {
    try {
      const { data, error } = await supabase
        .from('user_notification_preferences')
        .select('channel_preferences, workflow_preferences, frequency_settings')
        .eq('user_id', userId)
        .maybeSingle();

      if (error && error.code !== 'PGRST116') {
        logger.error('Failed to fetch notification preferences', {
          action: 'fetch_notification_preferences',
          userId,
          error: error.message,
          errorCode: error.code
        });
        throw error;
      }

      if (!data) {
        logger.info('No preferences found, returning defaults', {
          action: 'fetch_notification_preferences',
          userId
        });
        return DEFAULT_NOTIFICATION_PREFERENCES;
      }

      // Validate the data from database
      return notificationPreferencesSchema.parse({
        channelPreferences: data.channel_preferences,
        workflowPreferences: data.workflow_preferences,
        frequencySettings: data.frequency_settings
      });
    } catch (error: unknown) {
      logger.error('Error fetching notification preferences', {
        action: 'fetch_notification_preferences',
        userId,
        error: error instanceof Error ? error.message : String(error)
      });
      return null;
    }
  }

  /**
   * Get notification templates
   */
  async getTemplates(): Promise<NotificationTemplate[]> {
    try {
      const { data, error } = await supabase
        .from('notification_templates')
        .select('*')
        .eq('is_active', true)
        .order('category', { ascending: true });

      if (error) {
        logger.error('Failed to fetch notification templates', {
          action: 'fetch_notification_templates',
          error: error.message,
          errorCode: error.code
        });
        throw error;
      }

      return (data || []).map(t => ({
        ...t,
        is_active: t.is_active ?? true,
        description: t.description || null,
        novu_workflow_id: t.novu_workflow_id || null,
      }));
    } catch (error: unknown) {
      logger.error('Error fetching notification templates', {
        action: 'fetch_notification_templates',
        error: error instanceof Error ? error.message : String(error)
      });
      return [];
    }
  }

  /**
   * Trigger a notification workflow
   */
  async trigger(payload: NotificationPayload): Promise<{ success: boolean; error?: string }> {
    try {
      const novuEnabled = await this.isNovuEnabled();
      if (!novuEnabled) {
        logger.warn('Novu not configured, skipping notification', {
          action: 'trigger_notification',
          workflowId: payload.workflowId,
          subscriberId: payload.subscriberId
        });
        return { success: false, error: 'Novu not configured' };
      }

      const { data, error, requestId } = await invokeWithTracking(
        'trigger-notification',
        payload
      );

      if (error) {
        logger.error('Failed to trigger notification', {
          action: 'trigger_notification',
          workflowId: payload.workflowId,
          subscriberId: payload.subscriberId,
          requestId,
          error: error.message
        });
        throw error;
      }

      logger.info('Notification triggered successfully', {
        action: 'trigger_notification',
        workflowId: payload.workflowId,
        subscriberId: payload.subscriberId,
        transactionId: data?.transactionId,
        requestId
      });

      return { success: true };
    } catch (error: unknown) {
      logger.error('Error triggering notification', {
        action: 'trigger_notification',
        workflowId: payload.workflowId,
        subscriberId: payload.subscriberId,
        error: error instanceof Error ? error.message : String(error)
      });

      return {
        success: false,
        error: 'Failed to trigger notification'
      };
    }
  }

  /**
   * Notify moderators (legacy method for backward compatibility)
   */
  async notifyModerators(payload: {
    submission_id: string;
    submission_type: string;
    submitter_name: string;
    action: string;
  }): Promise<void> {
    try {
      const { error, requestId } = await invokeWithTracking(
        'notify-moderators-submission',
        payload
      );

      if (error) {
        logger.error('Failed to notify moderators', {
          action: 'notify_moderators',
          submissionId: payload.submission_id,
          requestId,
          error: error.message
        });
        throw error;
      }

      logger.info('Moderators notified successfully', {
        action: 'notify_moderators',
        submissionId: payload.submission_id,
        requestId
      });
    } catch (error: unknown) {
      logger.error('Error notifying moderators', {
        action: 'notify_moderators',
        submissionId: payload.submission_id,
        error: error instanceof Error ? error.message : String(error)
      });
    }
  }

  /**
   * Trigger a system announcement to all users via the "users" topic
   * Requires admin or superuser role
   */
  async sendSystemAnnouncement(payload: {
    title: string;
    message: string;
    severity: 'info' | 'warning' | 'critical';
    actionUrl?: string;
  }): Promise<{ success: boolean; error?: string; announcementId?: string }> {
    try {
      const novuEnabled = await this.isNovuEnabled();
      if (!novuEnabled) {
        logger.warn('Novu not configured, skipping system announcement', {
          action: 'send_system_announcement',
          title: payload.title
        });
        return { success: false, error: 'Novu not configured' };
      }

      const { data, error, requestId } = await invokeWithTracking(
        'notify-system-announcement',
        payload
      );

      if (error) {
        logger.error('Failed to send system announcement', {
          action: 'send_system_announcement',
          title: payload.title,
          requestId,
          error: error.message
        });
        throw error;
      }

      logger.info('System announcement sent successfully', {
        action: 'send_system_announcement',
        title: payload.title,
        announcementId: data?.announcementId,
        requestId
      });

      return { 
        success: true,
        announcementId: data?.announcementId
      };
    } catch (error: unknown) {
      logger.error('Error sending system announcement', {
        action: 'send_system_announcement',
        title: payload.title,
        error: error instanceof Error ? error.message : String(error)
      });

      return {
        success: false,
        error: error instanceof Error ? error.message : 'Failed to send system announcement'
      };
    }
  }

  /**
   * Notify moderators about a new report via the "moderation-reports" topic
   */
  async notifyModeratorsReport(payload: {
    reportId: string;
    reportType: string;
    reportedEntityType: string;
    reportedEntityId: string;
    reporterName: string;
    reason: string;
    entityPreview: string;
    reportedAt: string;
  }): Promise<{ success: boolean; error?: string }> {
    try {
      const novuEnabled = await this.isNovuEnabled();
      if (!novuEnabled) {
        logger.warn('Novu not configured, skipping report notification', {
          action: 'notify_moderators_report',
          reportId: payload.reportId
        });
        return { success: false, error: 'Novu not configured' };
      }

      const { data, error, requestId } = await invokeWithTracking(
        'notify-moderators-report',
        payload
      );

      if (error) {
        logger.error('Failed to notify moderators about report', {
          action: 'notify_moderators_report',
          reportId: payload.reportId,
          requestId,
          error: error.message
        });
        throw error;
      }

      logger.info('Moderators notified about report successfully', {
        action: 'notify_moderators_report',
        reportId: payload.reportId,
        requestId
      });

      return { success: true };
    } catch (error: unknown) {
      logger.error('Error notifying moderators about report', {
        action: 'notify_moderators_report',
        reportId: payload.reportId,
        error: error instanceof Error ? error.message : String(error)
      });

      return {
        success: false,
        error: 'Failed to notify moderators about report'
      };
    }
  }

  /**
   * Check if notifications are enabled
   */
  isEnabled(): boolean {
    return true; // Always return true, actual check happens in isNovuEnabled()
  }
}

export const notificationService = new NotificationService();
