import { supabase } from "@/lib/supabaseClient";
import { invokeWithTracking } from "@/lib/edgeFunctionTracking";
import { handleNonCriticalError, 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) {
      handleNonCriticalError(error, {
        action: 'Check Novu Status',
        metadata: { returnedFalse: true }
      });
      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) {
        return { success: false, error: 'Novu not configured' };
      }

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

      if (error) {
        handleNonCriticalError(error, {
          action: 'Update Novu Subscriber (Edge Function)',
          userId: validated.subscriberId,
          metadata: { requestId }
        });
        throw new AppError(
          'Failed to update notification subscriber',
          'NOTIFICATION_ERROR',
          error.message
        );
      }

      return { success: true };
    } catch (error: unknown) {
      handleNonCriticalError(error, {
        action: 'Update Novu Subscriber',
        userId: subscriberData.subscriberId
      });

      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) {
        return { success: false, error: 'Novu not configured' };
      }

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

      if (error) {
        handleNonCriticalError(error, {
          action: 'Create Novu Subscriber (Edge Function)',
          userId: validated.subscriberId,
          metadata: { requestId }
        });
        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) {
        handleNonCriticalError(dbError, {
          action: 'Store Subscriber Preferences',
          userId: validated.subscriberId
        });
        throw dbError;
      }

      return { success: true };
    } catch (error: unknown) {
      handleNonCriticalError(error, {
        action: 'Create Novu Subscriber',
        userId: subscriberData.subscriberId
      });

      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) {
          handleNonCriticalError(novuError, {
            action: 'Update Novu Preferences',
            userId,
            metadata: { requestId }
          });
          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) {
        handleNonCriticalError(dbError, {
          action: 'Save Notification Preferences',
          userId
        });
        throw dbError;
      }

      // Create audit log entry using relational tables
      const { data: auditLog, error: auditError } = await supabase
        .from('profile_audit_log')
        .insert([{
          user_id: userId,
          changed_by: userId,
          action: 'notification_preferences_updated',
          changes: {}, // Empty placeholder - actual changes stored in profile_change_fields table
        }])
        .select('id')
        .single();

      if (!auditError && auditLog) {
        // Write changes to relational profile_change_fields table
        const { writeProfileChangeFields } = await import('./auditHelpers');
        await writeProfileChangeFields(auditLog.id, {
          email_notifications: {
            old_value: previousPrefs?.channel_preferences,
            new_value: validated.channelPreferences,
          },
          workflow_preferences: {
            old_value: previousPrefs?.workflow_preferences,
            new_value: validated.workflowPreferences,
          },
          frequency_settings: {
            old_value: previousPrefs?.frequency_settings,
            new_value: validated.frequencySettings,
          },
        });
      }

      return { success: true };
    } catch (error: unknown) {
      handleNonCriticalError(error, {
        action: 'Update Notification Preferences',
        userId
      });

      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') {
        handleNonCriticalError(error, {
          action: 'Fetch Notification Preferences',
          userId
        });
        throw error;
      }

      if (!data) {
        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) {
      handleNonCriticalError(error, {
        action: 'Get Notification Preferences',
        userId
      });
      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) {
        handleNonCriticalError(error, {
          action: 'Fetch Notification Templates'
        });
        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) {
      handleNonCriticalError(error, {
        action: 'Get Notification Templates'
      });
      return [];
    }
  }

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

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

      if (error) {
        handleNonCriticalError(error, {
          action: 'Trigger Notification',
          metadata: { workflowId: payload.workflowId, subscriberId: payload.subscriberId, requestId }
        });
        throw error;
      }

      return { success: true };
    } catch (error: unknown) {
      handleNonCriticalError(error, {
        action: 'Trigger Notification',
        metadata: { workflowId: payload.workflowId, subscriberId: payload.subscriberId }
      });

      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) {
        handleNonCriticalError(error, {
          action: 'Notify Moderators (Submission)',
          metadata: { submissionId: payload.submission_id, requestId }
        });
        throw error;
      }
    } catch (error: unknown) {
      handleNonCriticalError(error, {
        action: 'Notify Moderators (Submission)',
        metadata: { submissionId: payload.submission_id }
      });
    }
  }

  /**
   * 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) {
        return { success: false, error: 'Novu not configured' };
      }

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

      if (error) {
        handleNonCriticalError(error, {
          action: 'Send System Announcement',
          metadata: { title: payload.title, requestId }
        });
        throw error;
      }

      return { 
        success: true,
        announcementId: data?.announcementId
      };
    } catch (error: unknown) {
      handleNonCriticalError(error, {
        action: 'Send System Announcement',
        metadata: { title: payload.title }
      });

      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) {
        return { success: false, error: 'Novu not configured' };
      }

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

      if (error) {
        handleNonCriticalError(error, {
          action: 'Notify Moderators (Report)',
          metadata: { reportId: payload.reportId, requestId }
        });
        throw error;
      }

      return { success: true };
    } catch (error: unknown) {
      handleNonCriticalError(error, {
        action: 'Notify Moderators (Report)',
        metadata: { reportId: payload.reportId }
      });

      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();
