import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';

/// Utility class to fix the fields table schema
class FixFieldsTableUtil {
  /// Fix the fields table schema
  static Future<void> fixFieldsTable(BuildContext context) async {
    try {
      // Show loading dialog
      showDialog(
        context: context,
        barrierDismissible: false,
        builder:
            (context) => const AlertDialog(
              content: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  CircularProgressIndicator(),
                  SizedBox(height: 16),
                  Text('Memperbaiki struktur tabel fields...'),
                ],
              ),
            ),
      );

      final client = Supabase.instance.client;

      // Clear cache first
      await _clearSupabaseCache();

      // Step 1: Check if updated_at column exists
      final columnsResult = await client
          .rpc(
            'check_column_exists',
            params: {'table_name': 'fields', 'column_name': 'updated_at'},
          )
          .timeout(const Duration(seconds: 10));

      print('Column check result: $columnsResult');

      // Step 2: Add updated_at column if it doesn't exist
      if (columnsResult == false) {
        await client
            .rpc(
              'execute_sql',
              params: {
                'sql_statement':
                    'ALTER TABLE public.fields ADD COLUMN updated_at TIMESTAMP WITH TIME ZONE DEFAULT now()',
              },
            )
            .timeout(const Duration(seconds: 10));
        print('Added updated_at column');
      }

      // Step 3: Create or replace the update trigger function
      await client
          .rpc(
            'execute_sql',
            params: {
              'sql_statement':
                  'CREATE OR REPLACE FUNCTION update_fields_updated_at() RETURNS TRIGGER AS \$\$ BEGIN NEW.updated_at = now(); RETURN NEW; END; \$\$ LANGUAGE plpgsql;',
            },
          )
          .timeout(const Duration(seconds: 10));
      print('Created trigger function');

      // Step 4: Create the trigger if it doesn't exist
      await client
          .rpc(
            'execute_sql',
            params: {
              'sql_statement':
                  'DROP TRIGGER IF EXISTS trigger_fields_updated_at ON public.fields; CREATE TRIGGER trigger_fields_updated_at BEFORE UPDATE ON public.fields FOR EACH ROW EXECUTE PROCEDURE update_fields_updated_at();',
            },
          )
          .timeout(const Duration(seconds: 10));
      print('Created trigger');

      // Step 5: Update all fields to set updated_at = created_at where null
      await client
          .rpc(
            'execute_sql',
            params: {
              'sql_statement':
                  'UPDATE public.fields SET updated_at = created_at WHERE updated_at IS NULL',
            },
          )
          .timeout(const Duration(seconds: 10));
      print('Updated null updated_at values');

      // Step 6: Fix RLS policies to avoid recursion issues
      await _fixRLSPolicies(client);

      // Close the dialog
      Navigator.pop(context);

      // Show success message
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('Struktur tabel fields berhasil diperbaiki'),
          backgroundColor: Colors.green,
        ),
      );
    } catch (e) {
      print('Error fixing fields table: $e');

      // Close the dialog if it's open
      Navigator.pop(context);

      // Show error message
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(
            'Gagal memperbaiki struktur tabel fields: ${e.toString()}',
          ),
          backgroundColor: Colors.red,
        ),
      );
    }
  }

  /// Fix RLS policies to avoid recursion issues
  static Future<void> _fixRLSPolicies(SupabaseClient client) async {
    try {
      // Fix user_roles policies
      await client
          .rpc(
            'execute_sql',
            params: {
              'sql_statement': '''
            -- Remove existing policies from user_roles
            DROP POLICY IF EXISTS "Users can view their own roles" ON public.user_roles;
            DROP POLICY IF EXISTS "Users can insert their own roles" ON public.user_roles;
            DROP POLICY IF EXISTS "Users can update their own roles" ON public.user_roles;
            DROP POLICY IF EXISTS "Users can delete their own roles" ON public.user_roles;
            
            -- Create simplified policies for user_roles
            CREATE POLICY "Enable read access for authenticated users" 
              ON public.user_roles FOR SELECT 
              USING (auth.role() = 'authenticated');
              
            CREATE POLICY "Enable insert access for authenticated users" 
              ON public.user_roles FOR INSERT 
              WITH CHECK (auth.role() = 'authenticated');
              
            CREATE POLICY "Enable update for users based on user_id" 
              ON public.user_roles FOR UPDATE
              USING (auth.uid() = user_id)
              WITH CHECK (auth.uid() = user_id);
              
            CREATE POLICY "Enable delete for users based on user_id" 
              ON public.user_roles FOR DELETE
              USING (auth.uid() = user_id);
          ''',
            },
          )
          .timeout(const Duration(seconds: 10));

      // Fix fields policies
      await client
          .rpc(
            'execute_sql',
            params: {
              'sql_statement': '''
            -- Remove existing policies from fields
            DROP POLICY IF EXISTS "Users can view their own fields" ON public.fields;
            DROP POLICY IF EXISTS "Users can insert their own fields" ON public.fields;
            DROP POLICY IF EXISTS "Users can update their own fields" ON public.fields;
            DROP POLICY IF EXISTS "Users can delete their own fields" ON public.fields;
            
            -- Create simplified policies for fields
            CREATE POLICY "Enable read access for authenticated users" 
              ON public.fields FOR SELECT 
              USING (auth.role() = 'authenticated');
              
            CREATE POLICY "Enable insert access for authenticated users" 
              ON public.fields FOR INSERT 
              WITH CHECK (auth.uid() = user_id);
              
            CREATE POLICY "Enable update for users based on user_id" 
              ON public.fields FOR UPDATE
              USING (auth.uid() = user_id)
              WITH CHECK (auth.uid() = user_id);
              
            CREATE POLICY "Enable delete for users based on user_id" 
              ON public.fields FOR DELETE
              USING (auth.uid() = user_id);
          ''',
            },
          )
          .timeout(const Duration(seconds: 10));

      print('Fixed RLS policies');
    } catch (e) {
      print('Error fixing RLS policies: $e');
      rethrow;
    }
  }

  /// Clear Supabase cache to help with stuck issues
  static Future<void> _clearSupabaseCache() async {
    try {
      // Clear SharedPreferences cache
      final prefs = await SharedPreferences.getInstance();
      final keys =
          prefs
              .getKeys()
              .where(
                (key) =>
                    key.startsWith('supabase') ||
                    key.contains('auth') ||
                    key.contains('fields') ||
                    key.contains('cache'),
              )
              .toList();

      for (var key in keys) {
        await prefs.remove(key);
      }

      print('Cleared ${keys.length} cache entries');

      // Force refresh auth session
      try {
        await Supabase.instance.client.auth.refreshSession();
        print('Auth session refreshed');
      } catch (e) {
        print('Error refreshing auth session: $e');
        // Continue even if this fails
      }
    } catch (e) {
      print('Error clearing cache: $e');
      // Continue even if this fails
    }
  }

  /// Public method to clear cache
  static Future<void> clearCache() async {
    await _clearSupabaseCache();
  }
}
