/**
 * vite-plugin-supabase-sync
 *
 * Dev-only Vite plugin that keeps src/data/db/ in sync with Supabase.
 *
 * Behaviour:
 *  1. On dev server start → fetches ALL marketing_reports → writes src/data/db/{id}.json
 *  2. Subscribes to Supabase Realtime → re-writes the changed file → sends HMR full-reload
 *  3. Generates src/data/db/_index.json  (id → clinic_name map for quick lookup)
 *
 * The generated files are gitignored — they are local dev snapshots only.
 */

import { createClient } from '@supabase/supabase-js';
import { writeFileSync, mkdirSync, unlinkSync, existsSync } from 'fs';
import path from 'path';
import type { Plugin, ViteDevServer } from 'vite';

interface Options {
  supabaseUrl: string;
  serviceRoleKey: string;
  /** Output directory relative to project root. Default: src/data/db */
  outDir?: string;
}

type ReportRow = {
  id: string;
  clinic_name: string | null;
  url: string | null;
  status: string | null;
  report: Record<string, unknown> | null;
  channel_data: Record<string, unknown> | null;
  scrape_data: Record<string, unknown> | null;
  created_at: string;
  updated_at: string | null;
};

function writeReport(outDir: string, row: ReportRow) {
  const filePath = path.join(outDir, `${row.id}.json`);
  writeFileSync(filePath, JSON.stringify(row, null, 2), 'utf-8');
}

function writeIndex(outDir: string, rows: ReportRow[]) {
  const index = rows.map((r) => ({
    id: r.id,
    clinic_name: r.clinic_name,
    url: r.url,
    status: r.status,
    created_at: r.created_at,
    gu_rating: (r.channel_data as Record<string, Record<string, unknown>> | null)?.gangnamUnni?.rating ?? null,
    lead_doctor: (r.report as Record<string, Record<string, Record<string, unknown>>> | null)?.clinicInfo?.leadDoctor?.name ?? null,
  }));
  writeFileSync(path.join(outDir, '_index.json'), JSON.stringify(index, null, 2), 'utf-8');
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
async function syncAll(supabase: any, outDir: string, server?: ViteDevServer) {
  const { data, error } = await supabase
    .from('marketing_reports')
    .select('id, clinic_name, url, status, report, channel_data, scrape_data, created_at, updated_at')
    .order('created_at', { ascending: false });

  if (error) {
    console.error('[supabase-sync] fetch error:', error.message);
    return;
  }

  const rows = (data ?? []) as ReportRow[];
  for (const row of rows) writeReport(outDir, row);
  writeIndex(outDir, rows);

  console.log(`[supabase-sync] ✓ synced ${rows.length} report(s) → ${outDir}`);
  if (server) server.ws.send({ type: 'full-reload' });
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
async function syncOne(supabase: any, outDir: string, id: string, server: ViteDevServer) {
  const { data, error } = await supabase
    .from('marketing_reports')
    .select('id, clinic_name, url, status, report, channel_data, scrape_data, created_at, updated_at')
    .eq('id', id)
    .single();

  if (error || !data) {
    console.error(`[supabase-sync] fetch error for ${id}:`, error?.message);
    return;
  }

  writeReport(outDir, data as ReportRow);

  // Rebuild index
  const { data: all } = await supabase
    .from('marketing_reports')
    .select('id, clinic_name, url, status, report, channel_data, scrape_data, created_at, updated_at')
    .order('created_at', { ascending: false });
  if (all) writeIndex(outDir, all as ReportRow[]);

  console.log(`[supabase-sync] ✓ updated ${(data as ReportRow).clinic_name ?? id}`);
  server.ws.send({ type: 'full-reload' });
}

export function supabaseSync(options: Options): Plugin {
  const { supabaseUrl, serviceRoleKey, outDir: outDirOption } = options;

  return {
    name: 'vite-plugin-supabase-sync',
    apply: 'serve', // dev only — excluded from production build

    async configureServer(server) {
      if (!supabaseUrl || !serviceRoleKey) {
        console.warn('[supabase-sync] Missing SUPABASE_URL or SERVICE_ROLE_KEY — sync disabled');
        return;
      }

      const outDir = path.resolve(outDirOption ?? 'src/data/db');
      if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true });

      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      const supabase: any = createClient(supabaseUrl, serviceRoleKey, {
        auth: { persistSession: false },
      });

      // 1. Initial full sync
      await syncAll(supabase, outDir, undefined);

      // 2. Realtime subscription — fires on INSERT / UPDATE / DELETE
      supabase
        .channel('db-sync')
        .on(
          'postgres_changes',
          { event: '*', schema: 'public', table: 'marketing_reports' },
          async (payload) => {
            const newRow = payload.new as { id?: string } | undefined;
            const oldRow = payload.old as { id?: string } | undefined;
            const id = newRow?.id ?? oldRow?.id;
            if (!id) return;

            if (payload.eventType === 'DELETE') {
              const filePath = path.join(outDir, `${id}.json`);
              if (existsSync(filePath)) {
                unlinkSync(filePath);
                console.log(`[supabase-sync] ✓ removed ${id}.json`);
              }
              server.ws.send({ type: 'full-reload' });
            } else {
              await syncOne(supabase, outDir, id, server);
            }
          },
        )
        .subscribe((status) => {
          if (status === 'SUBSCRIBED') {
            console.log('[supabase-sync] Realtime subscription active');
          }
        });

      // Clean up on server close
      server.httpServer?.on('close', () => {
        supabase.removeAllChannels();
      });
    },
  };
}
