import { prisma } from '@shieldai/db';
import { detectChanges, shouldTriggerAlert } from './change-detector';
import { homeTitleAlertPipeline } from './alert.pipeline';
import {
  PropertySnapshot,
  SchedulerConfig,
  ScheduledScanResult,
} from './types';
import { v4 as uuidv4 } from 'uuid';

const DEFAULT_SCHEDULER_CONFIG: SchedulerConfig = {
  scanIntervalMinutes: 60,
  premiumScanIntervalMinutes: 30,
  maxPropertiesPerScan: 100,
  enabled: true,
};

export class HomeTitleSchedulerService {
  private config: SchedulerConfig;
  private timerId: NodeJS.Timeout | null = null;
  private running = false;
  private lastScanResult: ScheduledScanResult | null = null;

  constructor(config?: Partial<SchedulerConfig>) {
    this.config = { ...DEFAULT_SCHEDULER_CONFIG, ...config };
  }

  getConfig(): SchedulerConfig {
    return { ...this.config };
  }

  updateConfig(partial: Partial<SchedulerConfig>): void {
    this.config = { ...this.config, ...partial };
    if (partial.scanIntervalMinutes && this.timerId) {
      this.stop();
      this.start();
    }
  }

  start(): void {
    if (!this.config.enabled) return;

    const intervalMs = this.config.scanIntervalMinutes * 60 * 1000;
    this.running = true;

    this.timerId = setInterval(async () => {
      if (this.running) {
        try {
          const result = await this.runScan();
          this.lastScanResult = result;
        } catch (error) {
          console.error('[HomeTitleScheduler] Scan error:', error);
        }
      }
    }, intervalMs);

    console.log(
      `[HomeTitleScheduler] Started with ${this.config.scanIntervalMinutes}min interval`,
    );
  }

  stop(): void {
    this.running = false;
    if (this.timerId) {
      clearInterval(this.timerId);
      this.timerId = null;
    }
    console.log('[HomeTitleScheduler] Stopped');
  }

  async runScan(): Promise<ScheduledScanResult> {
    const scanId = uuidv4();
    const startedAt = new Date().toISOString();
    const errors: string[] = [];
    let changesDetected = 0;
    let alertsCreated = 0;
    let notificationsSent = 0;

    try {
      const subscriptions = await prisma.subscription.findMany({
        where: {
          status: 'active',
          tier: { in: ['plus', 'premium'] },
        },
        select: {
          id: true,
          userId: true,
          tier: true,
        },
        take: this.config.maxPropertiesPerScan,
      });

      for (const subscription of subscriptions) {
        try {
          const propertySnapshots = await this.fetchLatestSnapshots(
            subscription.userId,
          );

          for (const snapshot of propertySnapshots) {
            const previousSnapshot = await this.fetchPreviousSnapshot(
              snapshot.propertyId,
              snapshot.id,
              snapshot.capturedAt,
            );

            if (!previousSnapshot) continue;

            const result = detectChanges(previousSnapshot, snapshot);

            if (shouldTriggerAlert(result, 'moderate')) {
              changesDetected++;

              const alert = await homeTitleAlertPipeline.processChangeDetection(
                result,
                subscription.id,
                subscription.userId,
              );

              if (alert) {
                alertsCreated++;
                if (subscription.tier === 'premium') {
                  notificationsSent++;
                }
              }
            }
          }
        } catch (error) {
          const errorMsg = `Subscription ${subscription.id}: ${error instanceof Error ? error.message : String(error)}`;
          errors.push(errorMsg);
          console.error(`[HomeTitleScheduler] Subscription scan error:`, errorMsg);
        }
      }
    } catch (error) {
      const errorMsg = `Scan ${scanId}: ${error instanceof Error ? error.message : String(error)}`;
      errors.push(errorMsg);
      console.error(`[HomeTitleScheduler] Scan error:`, errorMsg);
    }

    const completedAt = new Date().toISOString();

    const scanResult: ScheduledScanResult = {
      scanId,
      propertiesScanned: changesDetected,
      changesDetected,
      alertsCreated,
      notificationsSent,
      errors,
      startedAt,
      completedAt,
    };

    return scanResult;
  }

  getLastScanResult(): ScheduledScanResult | null {
    return this.lastScanResult;
  }

  isRunning(): boolean {
    return this.running;
  }

  private async fetchLatestSnapshots(userId: string): Promise<PropertySnapshot[]> {
    const rawSnapshots = await prisma.$queryRaw<
      Array<Record<string, unknown>>
    >`
      SELECT "id", "propertyId", "capturedAt", "ownerName",
             "deedDate", "taxId", "propertyType",
             "taxAmount", "lienCount"
      FROM "PropertySnapshot"
      WHERE "propertyId" IN (
        SELECT "propertyId" FROM "WatchlistItem"
        WHERE "subscriptionId" IN (
          SELECT "id" FROM "Subscription" WHERE "userId" = ${userId}
        )
      )
      ORDER BY "capturedAt" DESC
      LIMIT ${this.config.maxPropertiesPerScan}
    `;

    return rawSnapshots.map(row => ({
      id: String(row.id),
      propertyId: String(row.propertyId),
      capturedAt: String(row.capturedAt),
      ownerName: String(row.ownerName),
      address: row.address ? JSON.parse(String(row.address)) : {},
      deedDate: row.deedDate ? String(row.deedDate) : undefined,
      taxId: row.taxId ? String(row.taxId) : undefined,
      propertyType: String(row.propertyType) as PropertySnapshot['propertyType'],
      taxAmount: row.taxAmount ? Number(row.taxAmount) : undefined,
      lienCount: row.lienCount ? Number(row.lienCount) : undefined,
    }));
  }

  private async fetchPreviousSnapshot(
    propertyId: string,
    currentSnapshotId: string,
    currentCapturedAt: string,
  ): Promise<PropertySnapshot | null> {
    const rawSnapshots = await prisma.$queryRaw<
      Array<Record<string, unknown>>
    >`
      SELECT "id", "propertyId", "capturedAt", "ownerName",
             "deedDate", "taxId", "propertyType",
             "taxAmount", "lienCount"
      FROM "PropertySnapshot"
      WHERE "propertyId" = ${propertyId}
        AND "capturedAt" < ${currentCapturedAt}
        AND "id" != ${currentSnapshotId}
      ORDER BY "capturedAt" DESC
      LIMIT 1
    `;

    if (rawSnapshots.length === 0) return null;

    const row = rawSnapshots[0];
    return {
      id: String(row.id),
      propertyId: String(row.propertyId),
      capturedAt: String(row.capturedAt),
      ownerName: String(row.ownerName),
      address: row.address ? JSON.parse(String(row.address)) : {},
      deedDate: row.deedDate ? String(row.deedDate) : undefined,
      taxId: row.taxId ? String(row.taxId) : undefined,
      propertyType: String(row.propertyType) as PropertySnapshot['propertyType'],
      taxAmount: row.taxAmount ? Number(row.taxAmount) : undefined,
      lienCount: row.lienCount ? Number(row.lienCount) : undefined,
    };
  }
}

export const homeTitleScheduler = new HomeTitleSchedulerService();
