import { createLogger } from "../logger.js";
import { readFile } from "fs/promises";
import { join } from "path";
import { glob } from "glob";

const logger = createLogger("ThemeChecker");

interface CheckSummary {
  errorCount: number;
  warningCount: number;
  suggestionCount: number;
  checkedFiles: number;
}

interface CheckResult {
  path: string;
  offenses: Array<{
    check: string;
    message: string;
    severity: "error" | "warning" | "suggestion";
    start: { line: number; character: number };
    end: { line: number; character: number };
  }>;
}

interface FormattedResults {
  errors: Array<{
    file: string;
    check: string;
    message: string;
    line: number;
    column: number;
  }>;
  warnings: Array<{
    file: string;
    check: string;
    message: string;
    line: number;
    column: number;
  }>;
  suggestions: Array<{
    file: string;
    check: string;
    message: string;
    line: number;
    column: number;
  }>;
  summary: CheckSummary;
}

export class ThemeChecker {
  private themeDir: string;

  constructor(themeDir: string) {
    this.themeDir = themeDir;
    logger.info("Theme checker initialized successfully");
  }

  /**
   * Check the entire theme for issues
   */
  public async checkTheme(): Promise<FormattedResults> {
    try {
      const files = await glob("**/*.{liquid,json}", { cwd: this.themeDir });
      const results = await Promise.all(
        files.map(async (file) => {
          const content = await readFile(join(this.themeDir, file), "utf-8");
          return this.checkFile(file, content);
        })
      );
      return this.formatResults(results);
    } catch (error) {
      logger.error("Theme check failed - " + (error as Error).message);
      throw error;
    }
  }

  /**
   * Check specific files in the theme
   */
  public async checkFiles(files: string[]): Promise<FormattedResults> {
    try {
      const results = await Promise.all(
        files.map(async (file) => {
          const content = await readFile(join(this.themeDir, file), "utf-8");
          return this.checkFile(file, content);
        })
      );
      return this.formatResults(results);
    } catch (error) {
      logger.error(
        "File check failed for files [" +
          files.join(", ") +
          "] - " +
          (error as Error).message
      );
      throw error;
    }
  }

  /**
   * Check a single file
   */
  private async checkFile(path: string, content: string): Promise<CheckResult> {
    // Basic checks for now
    const offenses = [];

    // Check for missing alt attributes on img tags
    const imgRegex = /<img[^>]+>/g;
    const altRegex = /alt=["'][^"']*["']/;
    let match;
    let line = 1;
    let lastIndex = 0;

    while ((match = imgRegex.exec(content)) !== null) {
      if (!altRegex.test(match[0])) {
        // Count lines up to this point
        const textUpToMatch = content.slice(lastIndex, match.index);
        line += (textUpToMatch.match(/\n/g) || []).length;

        offenses.push({
          check: "missing-alt",
          message: "Image tag is missing alt attribute",
          severity: "error",
          start: { line, character: 0 },
          end: { line, character: match[0].length },
        });
      }
      lastIndex = match.index;
    }

    // Check for invalid Liquid syntax
    const liquidRegex = /{%[^%}]*%}/g;
    line = 1;
    lastIndex = 0;

    while ((match = liquidRegex.exec(content)) !== null) {
      const tag = match[0];
      if (!/^{%\s*[a-z]+[^%}]*%}$/i.test(tag)) {
        // Count lines up to this point
        const textUpToMatch = content.slice(lastIndex, match.index);
        line += (textUpToMatch.match(/\n/g) || []).length;

        offenses.push({
          check: "invalid-liquid",
          message: "Invalid Liquid syntax",
          severity: "error",
          start: { line, character: 0 },
          end: { line, character: tag.length },
        });
      }
      lastIndex = match.index;
    }

    return { path, offenses };
  }

  /**
   * Format check results into a more usable structure
   */
  private formatResults(results: CheckResult[]): FormattedResults {
    try {
      const formatted: FormattedResults = {
        errors: [],
        warnings: [],
        suggestions: [],
        summary: {
          errorCount: 0,
          warningCount: 0,
          suggestionCount: 0,
          checkedFiles: results.length,
        },
      };

      for (const result of results) {
        for (const offense of result.offenses) {
          const offenseData = {
            file: result.path,
            check: offense.check,
            message: offense.message,
            line: offense.start.line,
            column: offense.start.character,
          };

          switch (offense.severity) {
            case "error":
              formatted.errors.push(offenseData);
              formatted.summary.errorCount++;
              break;
            case "warning":
              formatted.warnings.push(offenseData);
              formatted.summary.warningCount++;
              break;
            case "suggestion":
              formatted.suggestions.push(offenseData);
              formatted.summary.suggestionCount++;
              break;
          }
        }
      }

      logger.info(
        "Check results formatted successfully - " +
          JSON.stringify({
            errors: formatted.summary.errorCount,
            warnings: formatted.summary.warningCount,
            suggestions: formatted.summary.suggestionCount,
            files: formatted.summary.checkedFiles,
          })
      );

      return formatted;
    } catch (error) {
      logger.error(
        "Failed to format check results - " + (error as Error).message
      );
      throw error;
    }
  }
}
