import type { DevToolbarRule } from "./types.ts";
import { createIssue, isVisible } from "./helpers.ts";

export const imageRules: DevToolbarRule[] = [
  {
    id: "images/quality",
    category: "images",
    defaultSeverity: "warning",
    description: "Checks image loading, sizing and optimization.",
    run: ({ root, window }) => {
      const issues = [];
      for (const image of root.querySelectorAll<HTMLImageElement>("img")) {
        if (image.complete && image.naturalWidth === 0)
          issues.push(
            createIssue({
              ruleId: "images/broken",
              category: "images",
              severity: "error",
              title: "Image failed to load",
              message: `The image at ${image.currentSrc || image.src || "(empty source)"} could not be loaded.`,
              element: image,
              recommendation: "Verify the URL, file path and response content type.",
            }),
          );
        if (
          !image.hasAttribute("width") &&
          !image.hasAttribute("height") &&
          getComputedStyle(image).aspectRatio === "auto"
        )
          issues.push(
            createIssue({
              ruleId: "images/dimensions",
              category: "images",
              severity: "warning",
              title: "Image has no reserved dimensions",
              message: "This image may cause layout shift while loading.",
              element: image,
              recommendation: "Add width and height attributes or CSS aspect-ratio.",
            }),
          );
        const rect = image.getBoundingClientRect();
        if (isVisible(image) && image.naturalWidth > 0 && rect.width > image.naturalWidth * 1.25)
          issues.push(
            createIssue({
              ruleId: "images/upscaled",
              category: "images",
              severity: "warning",
              title: "Image is being enlarged",
              message: `Rendered width ${Math.round(rect.width)}px exceeds intrinsic width ${image.naturalWidth}px.`,
              element: image,
              recommendation: "Use a larger source image to avoid blurring.",
            }),
          );
        if (image.naturalWidth > rect.width * 2.5 && rect.width > 0)
          issues.push(
            createIssue({
              ruleId: "images/oversized-dimensions",
              category: "images",
              severity: "suggestion",
              title: "Image source may be oversized",
              message: `Intrinsic width ${image.naturalWidth}px is much larger than rendered width ${Math.round(rect.width)}px.`,
              element: image,
              recommendation: "Use srcset/sizes or a smaller generated image.",
              confidence: "medium",
            }),
          );
        if (rect.top > window.innerHeight * 1.5 && image.loading !== "lazy")
          issues.push(
            createIssue({
              ruleId: "images/lazy-below-fold",
              category: "images",
              severity: "suggestion",
              title: "Below-fold image is not lazy loaded",
              message: "This image starts far below the initial viewport.",
              element: image,
              recommendation: 'Consider loading="lazy".',
              confidence: "medium",
            }),
          );
        if (rect.top < window.innerHeight && image.loading === "lazy")
          issues.push(
            createIssue({
              ruleId: "images/lazy-above-fold",
              category: "images",
              severity: "suggestion",
              title: "Above-fold image is lazy loaded",
              message: "Lazy loading a visible hero image can delay rendering.",
              element: image,
              recommendation:
                'Remove lazy loading and consider fetchpriority="high" for the main hero image.',
              confidence: "medium",
            }),
          );
      }
      return issues;
    },
  },
];
