import { GitScanner } from './GitScanner.js';
import { StorybookScanner } from './StorybookScanner.js';
import { FigmaScanner } from './FigmaScanner.js';
import { ComponentMatcher } from './ComponentMatcher.js';
import ConfigService from '../services/ConfigService.js';
import Component from '../models/Component.js';
import Project from '../models/Project.js';
import sequelize from '../config/database.js';

/**
 * Orchestrator for component discovery.
 * Coordinates scanners, matching, and database persistence.
 */
export class ComponentScanner {
  constructor() {
    this.gitScanner = new GitScanner();
    this.sbScanner = new StorybookScanner();
    this.figmaScanner = new FigmaScanner();
    this.matcher = new ComponentMatcher();
  }

  /**
   * Executes full scan for a project.
   * @param {string} projectId - UUID of project to scan
   */
  async scan(projectId) {
    console.log(`[ComponentScanner] Starting scan for project ${projectId}`);

    // 1. Fetch Project and Configuration
    const project = await Project.findByPk(projectId);
    if (!project) {
      throw new Error(`Project not found: ${projectId}`);
    }

    // Get resolved configuration (System -> Project -> User cascade)
    const config = await ConfigService.resolveConfig(projectId);
    console.log(`[ComponentScanner] Configuration resolved`);

    // Get workspace path from project metadata or config
    const workspacePath = project.metadata?.workspacePath || config['component.directory'];

    // 2. Run Scanners in Parallel
    const [gitResults, sbResults, figmaResults] = await Promise.all([
      this.gitScanner.scan(workspacePath),
      this.sbScanner.scan(config['storybook.base_url']),
      this.figmaScanner.scan(config)
    ]);

    console.log(`[ComponentScanner] Scan results - Git: ${gitResults.length}, Storybook: ${sbResults.length}, Figma: ${figmaResults.length}`);

    // 3. Match Components
    const matches = this.matcher.match(gitResults, sbResults, figmaResults);
    console.log(`[ComponentScanner] Matched ${matches.length} components`);

    // 4. Persist Results (Transaction) - Use bulk upsert for performance
    const transaction = await sequelize.transaction();
    const stats = { discovered: matches.length, created: 0, updated: 0, matched: 0 };

    try {
      // Get existing components to determine created vs updated
      const existingComponents = await Component.findAll({
        where: {
          projectId,
          name: matches.map(m => m.name)
        },
        attributes: ['name'],
        raw: true,
        transaction
      });

      const existingNames = new Set(existingComponents.map(c => c.name));

      // Prepare bulk data
      const componentsData = matches.map(match => {
        const sourceCount = [match.sources.git, match.sources.storybook, match.sources.figma]
          .filter(Boolean).length;

        if (sourceCount > 1) {
          stats.matched++;
        }

        // Count created vs updated
        if (existingNames.has(match.name)) {
          stats.updated++;
        } else {
          stats.created++;
        }

        return {
          projectId,
          name: match.name,
          status: 'draft',
          description: match.sources.figma?.description || null,
          figmaId: match.sources.figma?.figmaId || null,
          storybookPath: match.sources.storybook?.storybookPath || null,
          variants: match.sources.storybook?.variants || null,
          metadata: {
            lastScan: new Date().toISOString(),
            sources: {
              git: match.sources.git ? {
                filePath: match.sources.git.filePath,
                lastModified: match.sources.git.lastModified
              } : null,
              storybook: match.sources.storybook ? {
                path: match.sources.storybook.storybookPath,
                variants: match.sources.storybook.variants
              } : null,
              figma: match.sources.figma ? {
                id: match.sources.figma.figmaId,
                description: match.sources.figma.description
              } : null
            }
          }
        };
      });

      // Bulk upsert all components in single operation
      await Component.bulkCreate(componentsData, {
        updateOnDuplicate: ['description', 'figmaId', 'storybookPath', 'variants', 'metadata'],
        transaction
      });

      await transaction.commit();

      console.log(`[ComponentScanner] Scan complete. Created: ${stats.created}, Updated: ${stats.updated}, Matched: ${stats.matched}`);
      return stats;

    } catch (error) {
      await transaction.rollback();
      console.error('[ComponentScanner] Database transaction failed:', error);
      throw error;
    }
  }
}
