/*
 * Copyright 2025 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hbasesoft.framework.ai.agent.tool.browser;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.microsoft.playwright.Playwright;

/**
 * Spring Boot environment Playwright initializer Handles the special requirements for running Playwright in Spring Boot
 * fat jar
 */
@Component
public class SpringBootPlaywrightInitializer {

    private static final Logger log = LoggerFactory.getLogger(SpringBootPlaywrightInitializer.class);

    /**
     * Initialize Playwright for Spring Boot environment
     */
    public Playwright createPlaywright() {
        try {
            // Set up environment for Spring Boot
            setupSpringBootEnvironment();

            // Save current context class loader
            ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();

            try {
                // Use this class's classloader (LaunchedClassLoader in Spring Boot)
                ClassLoader newCL = this.getClass().getClassLoader();
                log.info("Switching to ClassLoader: {} [{}]", newCL.getClass().getSimpleName(), newCL.toString());
                Thread.currentThread().setContextClassLoader(newCL);

                log.info("About to call Playwright.create()...");
                Playwright playwright = Playwright.create();
                log.info("Playwright.create() successful! Instance: {}", playwright.getClass().getName());

                // Check what was actually downloaded after creation
                log.info("=== Post-Creation Directory Check ===");
                String browserPath = System.getProperty("playwright.browsers.path");
                String tempDir = System.getProperty("playwright.driver.tmpdir");

                try {
                    Path browsersPath = Paths.get(browserPath);
                    if (Files.exists(browsersPath)) {
                        log.info("Browsers directory content:");
                        Files.walk(browsersPath, 2).forEach(path -> {
                            if (!path.equals(browsersPath)) {
                                log.info("  - {}", browsersPath.relativize(path));
                            }
                        });
                    }

                    // Check temp directory for playwright files
                    Path tempPath = Paths.get(tempDir);
                    if (Files.exists(tempPath)) {
                        Files.list(tempPath).filter(path -> path.getFileName().toString().contains("playwright"))
                            .forEach(path -> log.info("Temp playwright file: {}", path));
                    }
                }
                catch (Exception e) {
                    log.warn("Could not list post-creation directories: {}", e.getMessage());
                }
                log.info("=====================================");

                return playwright;
            }
            finally {
                // Always restore original class loader
                Thread.currentThread().setContextClassLoader(originalClassLoader);
            }
        }
        catch (Exception e) {
            log.error("Failed to create Playwright in Spring Boot environment", e);
            throw new RuntimeException("Failed to initialize Playwright", e);
        }
    }

    /**
     * Set up environment properties for Spring Boot
     */
    private void setupSpringBootEnvironment() {
        // Print detailed class loader information
        ClassLoader currentCL = Thread.currentThread().getContextClassLoader();
        ClassLoader thisCL = this.getClass().getClassLoader();

        log.info("=== Playwright Class Loader Analysis ===");
        log.info("Current thread context ClassLoader: {} [{}]", currentCL.getClass().getSimpleName(),
            currentCL.toString());
        log.info("This class ClassLoader: {} [{}]", thisCL.getClass().getSimpleName(), thisCL.toString());

        // Print classpath information
        String classPath = System.getProperty("java.class.path");
        log.info("Java classpath: {}", classPath);

        // Print loader path if exists
        String loaderPath = System.getProperty("loader.path");
        if (loaderPath != null) {
            log.info("Spring Boot loader.path: {}", loaderPath);
        }

        // Set browser path
        String browserPath = System.getProperty("user.home") + "/.cache/ms-playwright";
        System.setProperty("playwright.browsers.path", browserPath);

        // Set driver temp directory
        String tempDir = System.getProperty("java.io.tmpdir");
        System.setProperty("playwright.driver.tmpdir", tempDir);

        // Check if browsers are installed
        Path browsersPath = Paths.get(browserPath);
        if (Files.exists(browsersPath)) {
            log.info("Playwright browsers found at: {}", browserPath);
            System.setProperty("PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD", "1");
        }
        else {
            log.warn("Playwright browsers not found at: {}. They will be downloaded on first use.", browserPath);
        }

        log.info("Spring Boot Playwright environment configured:");
        log.info("  - Browser path: {}", browserPath);
        log.info("  - Temp directory: {}", tempDir);

        // Print all Playwright-related system properties
        log.info("=== Playwright Runtime Directories ===");
        log.info("  - playwright.browsers.path: {}", System.getProperty("playwright.browsers.path"));
        log.info("  - playwright.driver.tmpdir: {}", System.getProperty("playwright.driver.tmpdir"));
        log.info("  - PLAYWRIGHT_BROWSERS_PATH env: {}", System.getenv("PLAYWRIGHT_BROWSERS_PATH"));
        log.info("  - PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: {}", System.getProperty("PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD"));

        // Check actual directories
        String[] checkPaths = {
            browserPath, browserPath + "/chromium-*", browserPath + "/firefox-*", browserPath + "/webkit-*",
            tempDir + "/playwright-java-*"
        };

        for (String path : checkPaths) {
            try {
                Path p = Paths.get(path.replace("*", ""));
                if (Files.exists(p)) {
                    log.info("  ✓ Directory exists: {}", path);
                    if (Files.isDirectory(p)) {
                        Files.list(p).forEach(subPath -> log.info("    - {}", subPath.getFileName()));
                    }
                }
                else {
                    log.info("  ✗ Directory not found: {}", path);
                }
            }
            catch (Exception e) {
                log.warn("  ? Could not check path {}: {}", path, e.getMessage());
            }
        }

        log.info("==========================================");
    }

    /**
     * Check if Playwright can be initialized
     */
    public boolean canInitialize() {
        try {
            // Try to find the required classes
            Class.forName("com.microsoft.playwright.Playwright");
            return true;
        }
        catch (ClassNotFoundException e) {
            log.error("Playwright classes not found in classpath", e);
            return false;
        }
    }

}
