/*
 * Copyright (c), Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
 */

import GlyphAtlas from './GlyphAtlas';
import { EdgeProgram, NodeProgram, PolygonProgram, TextProgram } from './programs';

class ProgramManager {
    private device: GPUDevice;
    private format: GPUTextureFormat;
    private sampleCount: number;
    private uniformBindGroupLayout!: GPUBindGroupLayout;
    nodeProgram!: NodeProgram;
    edgeProgram!: EdgeProgram;
    textProgram!: TextProgram;
    clusterProgram!: PolygonProgram;
    fsgProgram!: PolygonProgram;
    highlightEdgeProgram!: EdgeProgram;
    highlightNodeProgram!: NodeProgram;

    constructor(device: GPUDevice, format: GPUTextureFormat, sampleCount = 4) {
        this.device = device;
        this.format = format;
        this.sampleCount = sampleCount;
    }

    async initialize(): Promise<void> {
        this.createUniformBindGroupLayout();
        this.nodeProgram = new NodeProgram(
            this.device,
            this.format,
            this.uniformBindGroupLayout,
            this.sampleCount
        );
        this.nodeProgram.initialize();
        this.edgeProgram = new EdgeProgram(
            this.device,
            this.format,
            this.uniformBindGroupLayout,
            this.sampleCount
        );
        this.edgeProgram.initialize();
        const atlas = await GlyphAtlas.create(this.device);
        this.textProgram = new TextProgram(
            this.device,
            this.format,
            this.uniformBindGroupLayout,
            atlas,
            this.sampleCount
        );
        this.textProgram.initialize();

        this.clusterProgram = new PolygonProgram(
            this.device,
            this.format,
            this.uniformBindGroupLayout,
            this.sampleCount
        );
        this.clusterProgram.initialize();

        this.clusterProgram = new PolygonProgram(
            this.device,
            this.format,
            this.uniformBindGroupLayout,
            this.sampleCount
        );
        this.clusterProgram.initialize();

        this.fsgProgram = new PolygonProgram(
            this.device,
            this.format,
            this.uniformBindGroupLayout,
            this.sampleCount
        );
        this.fsgProgram.initialize();

        this.highlightEdgeProgram = new EdgeProgram(
            this.device,
            this.format,
            this.uniformBindGroupLayout,
            this.sampleCount
        );
        this.highlightEdgeProgram.initialize();

        this.highlightNodeProgram = new NodeProgram(
            this.device,
            this.format,
            this.uniformBindGroupLayout,
            this.sampleCount
        );
        this.highlightNodeProgram.initialize();
    }

    private createUniformBindGroupLayout(): void {
        this.uniformBindGroupLayout = this.device.createBindGroupLayout({
            label: 'Uniform Bind Group Layout',
            entries: [
                {
                    binding: 0,
                    visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
                    buffer: { type: 'uniform' }
                }
            ]
        });
    }
}

export default ProgramManager;