/* eslint-disable @typescript-eslint/no-explicit-any */
import { LayerExtension } from '@deck.gl/core';

/**
 * LayerExtension that turns polygon fills into pie charts.
 *
 * Follows the canonical deck.gl v9 extension pattern:
 * - defaultProps with type:'accessor' enables getSubLayerProps() to wrap
 *   accessors via getSubLayerAccessor(), which unwraps __source.object to
 *   access the original data item through CompositeLayer sublayer chains.
 * - stepMode:'dynamic' handles per-instance counting automatically.
 * - isEnabled() restricts to SolidPolygonLayer (fill) sublayers only.
 *
 * Accepts the configured enum palette in the constructor.
 */

function paletteToGlsl(palette: [number, number, number][]): string {
  return palette
    .map(
      (c) =>
        `vec3(${(c[0] / 255).toFixed(4)}, ${(c[1] / 255).toFixed(4)}, ${(c[2] / 255).toFixed(4)})`
    )
    .join(',\n  ');
}

export class PieHexExtension extends LayerExtension {
  static extensionName = 'PieHexExtension';
  static defaultProps = {
    getCenter: { type: 'accessor', value: [0, 0] },
    getRatios0: { type: 'accessor', value: [1, 0, 0, 0] },
    getRatios1: { type: 'accessor', value: [0, 0, 0, 0] },
    getRatios2: { type: 'accessor', value: [0, 0] },
  };

  private paletteGlsl: string;

  constructor(palette: [number, number, number][]) {
    super();
    this.paletteGlsl = paletteToGlsl(palette);
  }

  isEnabled(layer: any): boolean {
    return layer.id.endsWith('-fill');
  }

  getShaders(this: any, extension: any): any {
    if (!extension.isEnabled(this)) return null;
    return {
      modules: [
        {
          name: 'pieHex',
          inject: {
            'vs:#decl': `\
in vec2 instancePieCenter;
in vec4 instanceRatios0;
in vec4 instanceRatios1;
in vec2 instanceRatios2;
out vec2 vPieCenter;
out vec2 vPieFragPos;
out vec4 vRatios0;
out vec4 vRatios1;
out vec2 vRatios2;`,
            'vs:#main-end': `\
vPieCenter = project_position(vec3(instancePieCenter, 0.0)).xy;
vPieFragPos = geometry.position.xy;
vRatios0 = instanceRatios0;
vRatios1 = instanceRatios1;
vRatios2 = instanceRatios2;`,
            'fs:#decl': `\
in vec2 vPieCenter;
in vec2 vPieFragPos;
in vec4 vRatios0;
in vec4 vRatios1;
in vec2 vRatios2;
const vec3 pieColors[10] = vec3[10](
  ${extension.paletteGlsl}
);`,
            'fs:DECKGL_FILTER_COLOR': `\
{
  vec2 delta = vPieFragPos - vPieCenter;
  float angle = atan(delta.x, -delta.y) / (2.0 * 3.14159265) + 0.5;

  float ratios[10];
  ratios[0] = vRatios0.x; ratios[1] = vRatios0.y;
  ratios[2] = vRatios0.z; ratios[3] = vRatios0.w;
  ratios[4] = vRatios1.x; ratios[5] = vRatios1.y;
  ratios[6] = vRatios1.z; ratios[7] = vRatios1.w;
  ratios[8] = vRatios2.x; ratios[9] = vRatios2.y;

  float cumulative = 0.0;
  vec3 sliceColor = pieColors[0];
  for (int i = 0; i < 10; i++) {
    cumulative += ratios[i];
    if (angle < cumulative) {
      sliceColor = pieColors[i];
      break;
    }
  }

  color = vec4(sliceColor, color.a);
}`,
          },
          uniformTypes: {},
        },
      ],
    };
  }

  initializeState(this: any, _context: any, extension: any): void {
    if (!extension.isEnabled(this)) return;
    const am = this.getAttributeManager();
    if (!am) return;
    am.add({
      instancePieCenter: {
        size: 2,
        stepMode: 'dynamic',
        accessor: 'getCenter',
      },
      instanceRatios0: {
        size: 4,
        stepMode: 'dynamic',
        accessor: 'getRatios0',
      },
      instanceRatios1: {
        size: 4,
        stepMode: 'dynamic',
        accessor: 'getRatios1',
      },
      instanceRatios2: {
        size: 2,
        stepMode: 'dynamic',
        accessor: 'getRatios2',
      },
    });
  }
}
