import { initializeApp, getApp, getApps } from 'firebase/app';
import { 
  getAuth, 
  signInWithEmailAndPassword, 
  createUserWithEmailAndPassword, 
  signOut, 
  onAuthStateChanged,
  getUser,
  GoogleAuthProvider,
  signInWithPopup
} from 'firebase/auth';
import { 
  getFirestore, 
  collection, 
  getDocs, 
  doc, 
  getDoc, 
  setDoc, 
  updateDoc, 
  deleteDoc, 
  query, 
  where, 
  orderBy, 
  limit, 
  onSnapshot 
} from 'firebase/firestore';
import { getStorage, ref, uploadBytes, getDownloadURL } from 'firebase/storage';

// Firebase Configuration from user
const firebaseConfig = {
  apiKey: "AIzaSyBdRUyA7LDtDReUA3TXDys71dSHgD2tOEA",
  authDomain: "ems-ritchennai1.firebaseapp.com",
  projectId: "ems-ritchennai1",
  storageBucket: "ems-ritchennai1.firebasestorage.app",
  messagingSenderId: "825363154108",
  appId: "1:825363154108:web:7b6d3430aa3b696fef3cb9",
  measurementId: "G-3W7ECQ52G1"
};

// Initialize main Firebase App
const app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApp();
const auth = getAuth(app);
const db = getFirestore(app);
const storage = getStorage(app);

/**
 * Real-time channel handler mapping Supabase real-time channels to Firestore onSnapshot
 */
class FirestoreChannel {
  private name: string;
  private listeners: (() => void)[] = [];

  constructor(name: string) {
    this.name = name;
  }

  on(event: string, filter: { event: string; schema: string; table: string; filter?: string }, callback: () => void) {
    const table = filter.table;
    const colRef = collection(db, table);
    let q: any = colRef;

    if (filter.filter) {
      const parts = filter.filter.split('=eq.');
      if (parts.length === 2) {
        const field = parts[0];
        const val = parts[1];
        q = query(colRef, where(field, '==', val));
      }
    }

    const unsubscribe = onSnapshot(q, () => {
      callback();
    }, (err) => {
      console.warn(`Firestore Channel ${this.name} snapshot error:`, err);
    });

    this.listeners.push(unsubscribe);
    return this;
  }

  subscribe() {
    return this;
  }

  unsubscribeAll() {
    this.listeners.forEach(unsub => unsub());
    this.listeners = [];
  }
}

/**
 * Firestore Query Builder adapter representing Supabase's from('table') syntax
 */
class FirestoreQueryBuilder {
  private table: string;
  private filters: { field: string; op: any; val: any }[] = [];
  private orderByField: string | null = null;
  private orderByDirection: 'asc' | 'desc' = 'asc';
  private limitCount: number | null = null;
  private isSingle = false;
  private selectFields = '*';
  private operation: 'select' | 'insert' | 'update' | 'delete' | 'upsert' = 'select';
  private payload: any = null;

  constructor(table: string) {
    this.table = table;
  }

  select(fields = '*') {
    this.selectFields = fields;
    this.operation = 'select';
    return this;
  }

  insert(data: any) {
    this.operation = 'insert';
    this.payload = data;
    return this;
  }

  update(data: any) {
    this.operation = 'update';
    this.payload = data;
    return this;
  }

  delete() {
    this.operation = 'delete';
    return this;
  }

  upsert(data: any) {
    this.operation = 'upsert';
    this.payload = data;
    return this;
  }

  eq(field: string, val: any) {
    this.filters.push({ field, op: '==', val });
    return this;
  }

  neq(field: string, val: any) {
    this.filters.push({ field, op: '!=', val });
    return this;
  }

  gt(field: string, val: any) {
    this.filters.push({ field, op: '>', val });
    return this;
  }

  gte(field: string, val: any) {
    this.filters.push({ field, op: '>=', val });
    return this;
  }

  lt(field: string, val: any) {
    this.filters.push({ field, op: '<', val });
    return this;
  }

  lte(field: string, val: any) {
    this.filters.push({ field, op: '<=', val });
    return this;
  }

  in(field: string, val: any[]) {
    this.filters.push({ field, op: 'in', val });
    return this;
  }

  order(field: string, options?: { ascending: boolean }) {
    this.orderByField = field;
    this.orderByDirection = options?.ascending === false ? 'desc' : 'asc';
    return this;
  }

  limit(count: number) {
    this.limitCount = count;
    return this;
  }

  single() {
    this.isSingle = true;
    return this;
  }

  maybeSingle() {
    this.isSingle = true;
    return this;
  }

  private async fetchDocs(): Promise<any[]> {
    const colRef = collection(db, this.table);
    let qConstraints: any[] = [];

    for (const filter of this.filters) {
      qConstraints.push(where(filter.field, filter.op, filter.val));
    }

    if (this.orderByField) {
      qConstraints.push(orderBy(this.orderByField, this.orderByDirection));
    }

    if (this.limitCount !== null) {
      qConstraints.push(limit(this.limitCount));
    }

    const q = query(colRef, ...qConstraints);
    const snap = await getDocs(q);
    return snap.docs.map(d => d.data());
  }

  async execute() {
    try {
      if (this.operation === 'insert') {
        const colRef = collection(db, this.table);
        const items = Array.isArray(this.payload) ? this.payload : [this.payload];
        const insertedItems: any[] = [];

        for (const item of items) {
          const docId = item.id || item.user_id || doc(colRef).id;
          const docRef = doc(db, this.table, String(docId));
          const finalItem = { ...item, id: docId };
          await setDoc(docRef, finalItem);
          insertedItems.push(finalItem);
        }

        const data = Array.isArray(this.payload) ? insertedItems : insertedItems[0];
        return { data: this.isSingle && Array.isArray(data) ? data[0] : data, error: null };
      }

      if (this.operation === 'update') {
        const docsToUpdate = await this.fetchDocs();
        const updatedItems: any[] = [];

        for (const docObj of docsToUpdate) {
          const docId = docObj.id || docObj.user_id;
          if (!docId) continue;
          const docRef = doc(db, this.table, String(docId));
          await updateDoc(docRef, this.payload);
          updatedItems.push({ ...docObj, ...this.payload });
        }

        const data = this.isSingle && updatedItems.length > 0 ? updatedItems[0] : updatedItems;
        return { data, error: null };
      }

      if (this.operation === 'delete') {
        const docsToDelete = await this.fetchDocs();

        for (const docObj of docsToDelete) {
          const docId = docObj.id || docObj.user_id;
          if (!docId) continue;
          const docRef = doc(db, this.table, String(docId));
          await deleteDoc(docRef);
        }

        const data = this.isSingle && docsToDelete.length > 0 ? docsToDelete[0] : docsToDelete;
        return { data, error: null };
      }

      if (this.operation === 'upsert') {
        const items = Array.isArray(this.payload) ? this.payload : [this.payload];
        const result: any[] = [];

        for (const item of items) {
          const docId = item.id || item.user_id || doc(collection(db, this.table)).id;
          const docRef = doc(db, this.table, String(docId));
          const finalItem = { ...item, id: docId };
          await setDoc(docRef, finalItem, { merge: true });
          result.push(finalItem);
        }

        const data = Array.isArray(this.payload) ? result : result[0];
        return { data: this.isSingle && Array.isArray(data) ? data[0] : data, error: null };
      }

      // Default: select
      let list = await this.fetchDocs();

      // Resolve joins if requested. E.g. select('*, events(title, category)')
      if (this.selectFields && this.selectFields.includes('events(')) {
        for (const item of list) {
          if (item.event_id) {
            const evRef = doc(db, 'events', String(item.event_id));
            const evSnap = await getDoc(evRef);
            if (evSnap.exists()) {
              const evData = evSnap.data();
              item.events = {
                title: evData.title,
                category: evData.category
              };
            } else {
              item.events = null;
            }
          }
        }
      }

      if (this.isSingle) {
        if (list.length === 0) {
          return { data: null, error: { message: 'Document not found', code: 'PGRST116' } };
        }
        return { data: list[0], error: null };
      }

      return { data: list, error: null };
    } catch (err: any) {
      console.error(`Error in ${this.operation} on ${this.table}:`, err);
      return { data: null, error: err };
    }
  }

  then(onfulfilled?: (value: any) => any, onrejected?: (reason: any) => any) {
    return this.execute().then(onfulfilled, onrejected);
  }
}

// Map supabase.auth
const supabaseAuth = {
  async signInWithOAuth({ provider }: { provider: string }) {
    if (provider !== 'google') {
      return { data: { provider: null }, error: new Error("Unsupported OAuth provider") };
    }
    try {
      const googleProvider = new GoogleAuthProvider();
      const credential = await signInWithPopup(auth, googleProvider);
      const user = {
        id: credential.user.uid,
        email: credential.user.email,
        user_metadata: {
          name: credential.user.displayName
        }
      };
      return { data: { user }, error: null };
    } catch (error: any) {
      console.error("Firebase Google Auth Signin Error:", error);
      return { data: { user: null }, error };
    }
  },

  async signInWithPassword({ email, password }: any) {
    try {
      const credential = await signInWithEmailAndPassword(auth, email, password);
      const user = {
        id: credential.user.uid,
        email: credential.user.email,
        user_metadata: {}
      };
      return { data: { user }, error: null };
    } catch (error: any) {
      console.error("Firebase Auth Signin Error:", error);
      return { data: { user: null }, error };
    }
  },

  async signUp({ email, password, options }: any) {
    try {
      const credential = await createUserWithEmailAndPassword(auth, email, password);
      const user = {
        id: credential.user.uid,
        email: credential.user.email,
        user_metadata: options?.data || {}
      };
      return { data: { user }, error: null };
    } catch (error: any) {
      console.error("Firebase Auth Signup Error:", error);
      return { data: { user: null }, error };
    }
  },

  async signOut() {
    try {
      await signOut(auth);
      return { error: null };
    } catch (error: any) {
      return { error };
    }
  },

  async getUser() {
    const currentUser = auth.currentUser;
    if (currentUser) {
      return {
        data: {
          user: {
            id: currentUser.uid,
            email: currentUser.email
          }
        },
        error: null
      };
    }
    return { data: { user: null }, error: null };
  },

  async getSession() {
    const currentUser = auth.currentUser;
    if (currentUser) {
      return {
        data: {
          session: {
            user: {
              id: currentUser.uid,
              email: currentUser.email
            }
          }
        },
        error: null
      };
    }
    return { data: { session: null }, error: null };
  },

  onAuthStateChange(callback: (event: string, session: any) => void) {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      if (user) {
        callback('SIGNED_IN', {
          user: {
            id: user.uid,
            email: user.email
          }
        });
      } else {
        callback('SIGNED_OUT', null);
      }
    });
    return {
      data: {
        subscription: {
          unsubscribe
        }
      }
    };
  }
};

// Map active channels
const activeChannels = new Map<any, FirestoreChannel>();

// Expose main supabase client
export const supabase = {
  auth: supabaseAuth,
  from(table: string) {
    return new FirestoreQueryBuilder(table);
  },
  channel(name: string) {
    const chan = new FirestoreChannel(name);
    activeChannels.set(chan, chan);
    return chan;
  },
  removeChannel(chan: any) {
    if (chan && typeof chan.unsubscribeAll === 'function') {
      chan.unsubscribeAll();
      activeChannels.delete(chan);
    }
  },
  storage: {
    from(bucket: string) {
      return {
        upload(path: string, blob: Blob, options?: any) {
          return new Promise(async (resolve, reject) => {
            try {
              const storageRef = ref(storage, `${bucket}/${path}`);
              const snap = await uploadBytes(storageRef, blob, {
                contentType: options?.contentType || blob.type
              });
              resolve({ data: snap, error: null });
            } catch (error) {
              resolve({ data: null, error });
            }
          });
        },
        getPublicUrl(path: string) {
          const storageRef = ref(storage, `${bucket}/${path}`);
          return {
            data: {
              publicUrl: `https://firebasestorage.googleapis.com/v0/b/${firebaseConfig.storageBucket}/o/${encodeURIComponent(`${bucket}/${path}`)}?alt=media`
            }
          };
        }
      };
    }
  }
};

/**
 * Creates a secondary App instance for administrative user signups.
 * This prevents the administrator's session from being overwritten.
 */
export const createAdminClient = () => {
  const adminAppName = 'AdminAuthApp';
  let adminApp;
  if (getApps().some(app => app.name === adminAppName)) {
    adminApp = getApp(adminAppName);
  } else {
    adminApp = initializeApp(firebaseConfig, adminAppName);
  }
  const adminAuth = getAuth(adminApp);

  return {
    auth: {
      async signUp({ email, password }: any) {
        try {
          const credential = await createUserWithEmailAndPassword(adminAuth, email, password);
          // Immediately sign out from the admin app so we don't store session
          await signOut(adminAuth);
          return { data: { user: { id: credential.user.uid, email: credential.user.email } }, error: null };
        } catch (error: any) {
          console.error("Firebase Admin Auth Signup Error:", error);
          return { data: { user: null }, error };
        }
      }
    }
  };
};

/**
 * Base64 upload helper mapping to Firebase Storage
 */
export const uploadToSupabase = async (
  base64String: string, 
  path: string, 
  bucket: string = 'rit-events'
): Promise<string> => {
  try {
    const parts = base64String.split(';base64,');
    if (parts.length < 2) throw new Error('Invalid base64 string');
    
    const contentType = parts[0].split(':')[1];
    const raw = window.atob(parts[1]);
    const rawLength = raw.length;
    const uInt8Array = new Uint8Array(rawLength);

    for (let i = 0; i < rawLength; ++i) {
      uInt8Array[i] = raw.charCodeAt(i);
    }

    const blob = new Blob([uInt8Array], { type: contentType });
    const storageRef = ref(storage, `${bucket}/${path}`);
    await uploadBytes(storageRef, blob, { contentType });
    const publicUrl = await getDownloadURL(storageRef);
    return publicUrl;
  } catch (error) {
    console.error('Firebase Storage Upload Error:', error);
    throw error;
  }
};

export const uploadImageToSupabase = uploadToSupabase;

// Automatic Seeder for domains if empty
(async () => {
  try {
    const colRef = collection(db, 'domains');
    const snap = await getDocs(colRef);
    if (snap.empty) {
      console.log('Domains collection is empty. Seeding initial domains...');
      const DOMAIN_MAP = {
        'TECHNICAL': [
          { name: 'CSE', description: 'Computer Science and Engineering', image: 'https://images.unsplash.com/photo-1517694712202-14dd9538aa97?auto=format&fit=crop&q=80&w=600', status: 'APPROVED', category: 'TECHNICAL' },
          { name: 'CSBS', description: 'Computer Science and Business Systems', image: 'https://images.unsplash.com/photo-1460925895917-afdab827c52f?auto=format&fit=crop&q=80&w=600', status: 'APPROVED', category: 'TECHNICAL' },
          { name: 'AIML', description: 'Artificial Intelligence and Machine Learning (AIML)', image: 'https://images.unsplash.com/photo-1677442136019-21780ecad995?auto=format&fit=crop&q=80&w=600', status: 'APPROVED', category: 'TECHNICAL' },
          { name: 'AIDS', description: 'AIDS', image: 'https://images.unsplash.com/photo-1509228627152-72ae9ae6848d?auto=format&fit=crop&q=80&w=600', status: 'APPROVED', category: 'TECHNICAL' },
          { name: 'IT', description: 'Information Technology', image: 'https://images.unsplash.com/photo-1498050108023-c5249f4df085?auto=format&fit=crop&q=80&w=600', status: 'APPROVED', category: 'TECHNICAL' },
          { name: 'ECE', description: 'ECE', image: 'https://images.unsplash.com/photo-1517077304055-6e89abbf09b0?auto=format&fit=crop&q=80&w=600', status: 'APPROVED', category: 'TECHNICAL' },
          { name: 'Mechanical', description: 'Mechanical', image: 'https://images.unsplash.com/photo-1537462715879-360eeb61a0ad?auto=format&fit=crop&q=80&w=600', status: 'APPROVED', category: 'TECHNICAL' },
          { name: 'Bio-tech', description: 'Bio-tech', image: 'https://images.unsplash.com/photo-1530210124550-912dc1381cb8?auto=format&fit=crop&q=80&w=600', status: 'APPROVED', category: 'TECHNICAL' },
          { name: 'CCE', description: 'CCE', image: 'https://images.unsplash.com/photo-1550751827-4bd374c3f58b?auto=format&fit=crop&q=80&w=600', status: 'APPROVED', category: 'TECHNICAL' },
          { name: 'VLSI', description: 'VLSI', image: 'https://images.unsplash.com/photo-1518770660439-4636190af475?auto=format&fit=crop&q=80&w=600', status: 'APPROVED', category: 'TECHNICAL' }
        ],
        'NON-TECHNICAL': [
          { name: 'Management', description: 'Management', image: 'https://images.unsplash.com/photo-1519389950473-47ba0277781c?auto=format&fit=crop&q=80&w=400', status: 'APPROVED', category: 'NON-TECHNICAL' },
          { name: 'Arts & Culture', description: 'Arts & Culture', image: 'https://images.unsplash.com/photo-1513364776144-60967b0f800f?auto=format&fit=crop&q=80&w=800', status: 'APPROVED', category: 'NON-TECHNICAL' },
          { name: 'Sports', description: 'Sports & Athletics', image: 'https://images.unsplash.com/photo-1552674605-db6ffd4facb5?auto=format&fit=crop&q=80&w=400', status: 'APPROVED', category: 'NON-TECHNICAL' },
          { name: 'Social Welfare', description: 'Social Service', image: 'https://images.unsplash.com/photo-1488521787991-ed7bbaae773c?auto=format&fit=crop&q=80&w=400', status: 'APPROVED', category: 'NON-TECHNICAL' }
        ],
        'WORKSHOP': [
          { name: 'Software Dev', description: 'Software Engineering', image: 'https://images.unsplash.com/photo-1633356122544-f134324a6cee?auto=format&fit=crop&q=80&w=400', status: 'APPROVED', category: 'WORKSHOP' },
          { name: 'Design', description: 'UI/UX Design', image: 'https://images.unsplash.com/photo-1561070791-2526d30994b5?auto=format&fit=crop&q=80&w=800', status: 'APPROVED', category: 'WORKSHOP' },
          { name: 'Cloud/DevOps', description: 'Cloud', image: 'https://images.unsplash.com/photo-1451187580459-43490279c0fa?auto=format&fit=crop&q=80&w=400', status: 'APPROVED', category: 'WORKSHOP' }
        ]
      };

      for (const [_, domains] of Object.entries(DOMAIN_MAP)) {
        for (const domain of domains) {
          const docId = doc(colRef).id;
          const docRef = doc(db, 'domains', docId);
          await setDoc(docRef, { ...domain, id: docId });
        }
      }
      console.log('Seeded domains successfully.');
    }
  } catch (err) {
    console.error('Automatic domains seeder failed:', err);
  }
})();