import { chromium, Page, Browser } from "playwright";
import * as fs from "fs";
import * as path from "path";

const BASE_URL = "http://localhost:9771";
const API_URL = "http://localhost:8080/api";
const OUTPUT_DIR = path.join(__dirname);

interface ComponentTestResult {
  componentType: string;
  screenId: number;
  status: "pass" | "fail" | "no_panel" | "not_found" | "error";
  errorMessage?: string;
  consoleErrors: string[];
  hasConfigPanel: boolean;
  screenshot?: string;
}

const COMPONENT_SCREEN_MAP: Record<string, number> = {
  "v2-input": 60,
  "v2-select": 71,
  "v2-date": 77,
  "v2-button-primary": 47,
  "v2-text-display": 114,
  "v2-table-list": 47,
  "v2-table-search-widget": 79,
  "v2-media": 74,
  "v2-split-panel-layout": 74,
  "v2-tabs-widget": 1011,
  "v2-section-card": 1188,
  "v2-section-paper": 202,
  "v2-card-display": 83,
  "v2-numbering-rule": 130,
  "v2-repeater": 1188,
  "v2-divider-line": 1195,
  "v2-location-swap-selector": 1195,
  "v2-category-manager": 135,
  "v2-file-upload": 138,
  "v2-pivot-grid": 2327,
  "v2-rack-structure": 1575,
  "v2-repeat-container": 2403,
  "v2-split-line": 4151,
  "v2-bom-item-editor": 4154,
  "v2-process-work-standard": 4158,
  "v2-aggregation-widget": 4119,
  "flow-widget": 77,
  "entity-search-input": 3986,
  "select-basic": 4470,
  "textarea-basic": 3986,
  "selected-items-detail-input": 227,
  "screen-split-panel": 1674,
  "split-panel-layout2": 2089,
  "universal-form-modal": 2180,
  "v2-table-grouped": 79,
  "v2-status-count": 4498,
  "v2-timeline-scheduler": 79,
};

async function login(page: Page): Promise<string> {
  await page.goto(`${BASE_URL}/login`);
  await page.waitForLoadState("networkidle");
  await page.getByPlaceholder("사용자 ID를 입력하세요").fill("wace");
  await page.getByPlaceholder("비밀번호를 입력하세요").fill("qlalfqjsgh11");
  await page.getByRole("button", { name: "로그인" }).click();
  await page.waitForTimeout(5000);

  const token = await page.evaluate(() => localStorage.getItem("authToken") || "");
  console.log("Login token obtained:", token ? "YES" : "NO");
  return token;
}

async function openDesigner(page: Page, screenId: number): Promise<boolean> {
  await page.evaluate(() => {
    sessionStorage.setItem(
      "erp-tab-store",
      JSON.stringify({
        state: {
          tabs: [
            {
              id: "tab-screenmng",
              title: "화면 관리",
              path: "/admin/screenMng/screenMngList",
              isActive: true,
              isPinned: false,
            },
          ],
          activeTabId: "tab-screenmng",
        },
        version: 0,
      })
    );
  });

  await page.goto(`${BASE_URL}/admin/screenMng/screenMngList?openDesigner=${screenId}`);
  await page.waitForTimeout(8000);

  const designerOpen = await page.locator('[class*="designer"], [class*="canvas"], [data-testid*="designer"]').count();
  const hasComponents = await page.locator('[data-component-id], [class*="component-wrapper"]').count();
  console.log(`  Designer elements: ${designerOpen}, Components: ${hasComponents}`);
  return designerOpen > 0 || hasComponents > 0;
}

async function testComponentConfigPanel(
  page: Page,
  componentType: string,
  screenId: number
): Promise<ComponentTestResult> {
  const result: ComponentTestResult = {
    componentType,
    screenId,
    status: "error",
    consoleErrors: [],
    hasConfigPanel: false,
  };

  const consoleErrors: string[] = [];
  const pageErrors: string[] = [];

  page.on("console", (msg) => {
    if (msg.type() === "error") {
      consoleErrors.push(msg.text());
    }
  });
  page.on("pageerror", (err) => {
    pageErrors.push(err.message);
  });

  try {
    const opened = await openDesigner(page, screenId);
    if (!opened) {
      result.status = "error";
      result.errorMessage = "Designer failed to open";
      return result;
    }

    // find component by its url or type attribute in the DOM
    const componentUrl = componentType.startsWith("v2-")
      ? `@/lib/registry/components/${componentType}`
      : `@/lib/registry/components/${componentType}`;

    // Try clicking on a component of this type
    // The screen designer renders components with data attributes
    const componentSelector = `[data-component-type="${componentType}"], [data-component-url*="${componentType}"]`;
    const componentCount = await page.locator(componentSelector).count();

    if (componentCount === 0) {
      // Try alternative: look for components in the canvas by clicking around
      // First try to find any clickable component wrapper
      const wrappers = page.locator('[data-component-id]');
      const wrapperCount = await wrappers.count();

      if (wrapperCount === 0) {
        result.status = "not_found";
        result.errorMessage = `No components found in screen ${screenId}`;
        return result;
      }

      // Click the first component to see if panel opens
      let foundTarget = false;
      for (let i = 0; i < Math.min(wrapperCount, 20); i++) {
        try {
          await wrappers.nth(i).click({ force: true, timeout: 2000 });
          await page.waitForTimeout(1000);

          // Check if the properties panel shows the right component type
          const panelText = await page.locator('[class*="properties"], [class*="config-panel"], [class*="setting"]').textContent().catch(() => "");
          if (panelText && panelText.includes(componentType)) {
            foundTarget = true;
            break;
          }
        } catch {
          continue;
        }
      }

      if (!foundTarget) {
        result.status = "not_found";
        result.errorMessage = `Component type "${componentType}" not clickable in screen ${screenId}`;
      }
    } else {
      await page.locator(componentSelector).first().click({ force: true });
      await page.waitForTimeout(2000);
    }

    // Check for the config panel in the right sidebar
    await page.waitForTimeout(2000);

    // Look for config panel indicators
    const configPanelVisible = await page.evaluate(() => {
      // Check for error boundaries or error messages
      const errorElements = document.querySelectorAll('[class*="error"], [class*="Error"]');
      const errorTexts: string[] = [];
      errorElements.forEach((el) => {
        const text = el.textContent || "";
        if (text.includes("로드 실패") || text.includes("에러") || text.includes("Error") || text.includes("Cannot read")) {
          errorTexts.push(text.substring(0, 200));
        }
      });

      // Check for config panel elements
      const hasTabs = document.querySelectorAll('button[role="tab"]').length > 0;
      const hasLabels = document.querySelectorAll("label").length > 0;
      const hasInputs = document.querySelectorAll('input, select, [role="combobox"]').length > 0;
      const hasConfigContent = document.querySelectorAll('[class*="config"], [class*="panel"], [class*="properties"]').length > 0;
      const hasEditTab = Array.from(document.querySelectorAll("button")).some((b) => b.textContent?.includes("편집"));

      return {
        errorTexts,
        hasTabs,
        hasLabels,
        hasInputs,
        hasConfigContent,
        hasEditTab,
      };
    });

    result.hasConfigPanel = configPanelVisible.hasConfigContent || configPanelVisible.hasEditTab;

    // Take screenshot
    const screenshotName = `${componentType.replace(/[^a-zA-Z0-9-]/g, "_")}.png`;
    const screenshotPath = path.join(OUTPUT_DIR, screenshotName);
    await page.screenshot({ path: screenshotPath, fullPage: false });
    result.screenshot = screenshotName;

    // Collect errors
    result.consoleErrors = [...consoleErrors, ...pageErrors];

    if (configPanelVisible.errorTexts.length > 0) {
      result.status = "fail";
      result.errorMessage = configPanelVisible.errorTexts.join("; ");
    } else if (pageErrors.length > 0) {
      result.status = "fail";
      result.errorMessage = pageErrors.join("; ");
    } else if (consoleErrors.some((e) => e.includes("Cannot read") || e.includes("is not a function") || e.includes("undefined"))) {
      result.status = "fail";
      result.errorMessage = consoleErrors.filter((e) => e.includes("Cannot read") || e.includes("is not a function")).join("; ");
    } else {
      result.status = "pass";
    }
  } catch (err: any) {
    result.status = "error";
    result.errorMessage = err.message;
  }

  return result;
}

async function main() {
  console.log("=== Config Panel Full Audit ===");
  console.log(`Testing ${Object.keys(COMPONENT_SCREEN_MAP).length} component types\n`);

  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext({ viewport: { width: 1920, height: 1080 } });
  const page = await context.newPage();

  // Login
  const token = await login(page);
  if (!token) {
    console.error("Login failed!");
    await browser.close();
    return;
  }

  const results: ComponentTestResult[] = [];
  const componentTypes = Object.keys(COMPONENT_SCREEN_MAP);

  for (let i = 0; i < componentTypes.length; i++) {
    const componentType = componentTypes[i];
    const screenId = COMPONENT_SCREEN_MAP[componentType];
    console.log(`\n[${i + 1}/${componentTypes.length}] Testing: ${componentType} (screen: ${screenId})`);

    const result = await testComponentConfigPanel(page, componentType, screenId);
    results.push(result);

    const statusEmoji = {
      pass: "OK",
      fail: "FAIL",
      no_panel: "NO_PANEL",
      not_found: "NOT_FOUND",
      error: "ERROR",
    }[result.status];
    console.log(`  Result: ${statusEmoji} ${result.errorMessage || ""}`);

    // Clear console listeners for next iteration
    page.removeAllListeners("console");
    page.removeAllListeners("pageerror");
  }

  await browser.close();

  // Write results
  const reportPath = path.join(OUTPUT_DIR, "audit-results.json");
  fs.writeFileSync(reportPath, JSON.stringify(results, null, 2));

  // Summary
  console.log("\n\n=== AUDIT SUMMARY ===");
  const passed = results.filter((r) => r.status === "pass");
  const failed = results.filter((r) => r.status === "fail");
  const errors = results.filter((r) => r.status === "error");
  const notFound = results.filter((r) => r.status === "not_found");

  console.log(`PASS: ${passed.length}`);
  console.log(`FAIL: ${failed.length}`);
  console.log(`ERROR: ${errors.length}`);
  console.log(`NOT_FOUND: ${notFound.length}`);

  if (failed.length > 0) {
    console.log("\n--- FAILED Components ---");
    failed.forEach((r) => {
      console.log(`  ${r.componentType} (screen: ${r.screenId}): ${r.errorMessage}`);
    });
  }

  if (errors.length > 0) {
    console.log("\n--- ERROR Components ---");
    errors.forEach((r) => {
      console.log(`  ${r.componentType} (screen: ${r.screenId}): ${r.errorMessage}`);
    });
  }

  // Write markdown report
  const mdReport = generateMarkdownReport(results);
  fs.writeFileSync(path.join(OUTPUT_DIR, "audit-report.md"), mdReport);
  console.log(`\nReport saved to ${OUTPUT_DIR}/audit-report.md`);
}

function generateMarkdownReport(results: ComponentTestResult[]): string {
  const lines: string[] = [];
  lines.push("# Config Panel Audit Report");
  lines.push(`\nDate: ${new Date().toISOString()}`);
  lines.push(`\nTotal: ${results.length} components tested\n`);

  const passed = results.filter((r) => r.status === "pass");
  const failed = results.filter((r) => r.status === "fail");
  const errors = results.filter((r) => r.status === "error");
  const notFound = results.filter((r) => r.status === "not_found");

  lines.push(`| Status | Count |`);
  lines.push(`|--------|-------|`);
  lines.push(`| PASS | ${passed.length} |`);
  lines.push(`| FAIL | ${failed.length} |`);
  lines.push(`| ERROR | ${errors.length} |`);
  lines.push(`| NOT_FOUND | ${notFound.length} |`);

  lines.push(`\n## Failed Components\n`);
  if (failed.length === 0) {
    lines.push("None\n");
  } else {
    lines.push(`| Component | Screen ID | Error |`);
    lines.push(`|-----------|-----------|-------|`);
    failed.forEach((r) => {
      lines.push(`| ${r.componentType} | ${r.screenId} | ${(r.errorMessage || "").substring(0, 100)} |`);
    });
  }

  lines.push(`\n## Error Components\n`);
  if (errors.length === 0) {
    lines.push("None\n");
  } else {
    lines.push(`| Component | Screen ID | Error |`);
    lines.push(`|-----------|-----------|-------|`);
    errors.forEach((r) => {
      lines.push(`| ${r.componentType} | ${r.screenId} | ${(r.errorMessage || "").substring(0, 100)} |`);
    });
  }

  lines.push(`\n## Not Found Components\n`);
  if (notFound.length === 0) {
    lines.push("None\n");
  } else {
    notFound.forEach((r) => {
      lines.push(`- ${r.componentType} (screen: ${r.screenId}): ${r.errorMessage}`);
    });
  }

  lines.push(`\n## All Results\n`);
  lines.push(`| # | Component | Screen | Status | Config Panel | Error |`);
  lines.push(`|---|-----------|--------|--------|--------------|-------|`);
  results.forEach((r, i) => {
    const status = r.status.toUpperCase();
    lines.push(
      `| ${i + 1} | ${r.componentType} | ${r.screenId} | ${status} | ${r.hasConfigPanel ? "Yes" : "No"} | ${(r.errorMessage || "-").substring(0, 80)} |`
    );
  });

  return lines.join("\n");
}

main().catch(console.error);
