package cn.yunzhixue.ability.center.examsprint.infrastructure.report.pdf;

import cn.yunzhixue.ability.center.examsprint.domain.report.ExamSprintReportPdfGenerator;
import com.microsoft.playwright.BrowserType;
import org.springframework.beans.factory.DisposableBean;

import java.util.Objects;

public class PlaywrightExamSprintReportPdfGenerator implements ExamSprintReportPdfGenerator, DisposableBean, AutoCloseable {

    private static final double DEFAULT_LAUNCH_TIMEOUT_MILLIS = 30_000;
    private static final double DEFAULT_RENDER_TIMEOUT_MILLIS = 30_000;

    private final Object workerLock = new Object();
    private final PlaywrightPdfWorkerFactory workerFactory;
    private PlaywrightPdfWorker worker;
    private boolean closed;

    public PlaywrightExamSprintReportPdfGenerator() {
        this(DEFAULT_LAUNCH_TIMEOUT_MILLIS, DEFAULT_RENDER_TIMEOUT_MILLIS);
    }

    PlaywrightExamSprintReportPdfGenerator(double launchTimeoutMillis, double renderTimeoutMillis) {
        this(new DefaultPlaywrightPdfWorkerFactory(launchTimeoutMillis, renderTimeoutMillis));
    }

    PlaywrightExamSprintReportPdfGenerator(PlaywrightPdfWorkerFactory workerFactory) {
        this.workerFactory = Objects.requireNonNull(workerFactory, "workerFactory");
    }

    @Override
    public byte[] generate(String htmlContent) {
        Objects.requireNonNull(htmlContent, "htmlContent");

        // Playwright Java objects are not safe for unsynchronized concurrent use; keep this adapter
        // intentionally single-worker until throughput requirements justify a pool.
        synchronized (workerLock) {
            ensureOpen();
            return worker().generate(htmlContent);
        }
    }

    @Override
    public void destroy() {
        synchronized (workerLock) {
            if (closed) {
                return;
            }
            RuntimeException closeFailure = null;
            try {
                if (worker != null) {
                    worker.close();
                }
            } catch (RuntimeException exception) {
                closeFailure = exception;
            }
            closed = true;
            if (closeFailure != null) {
                throw closeFailure;
            }
        }
    }

    @Override
    public void close() {
        destroy();
    }

    private void ensureOpen() {
        if (closed) {
            throw new IllegalStateException("PDF generator is closed");
        }
    }

    private PlaywrightPdfWorker worker() {
        if (worker == null) {
            worker = Objects.requireNonNull(workerFactory.create(), "worker");
        }
        return worker;
    }

    static BrowserType.LaunchOptions createLaunchOptions(double launchTimeoutMillis) {
        return DefaultPlaywrightPdfWorker.createLaunchOptions(launchTimeoutMillis);
    }
}
