import type { CramFileBlock } from '../file.ts'
import type { DataType } from './dataSeriesTypes.ts'
import type CramSlice from '../slice/index.ts'

export interface DataTypeMapping {
  byte: number
  int: number
  long: number
  byteArray: Uint8Array
}

export interface Cursor {
  bitPosition: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
  bytePosition: number
}

export interface PreDecodedIntBlock {
  values: Int32Array
  index: number
}

export interface Cursors {
  lastAlignmentStart: number
  coreBlock: Cursor
  externalBlocks: {
    getCursor: (contentId: number) => Cursor
  }
  preDecodedIntBlocks?: Map<number, PreDecodedIntBlock>
}

// codec base class
export default abstract class CramCodec<
  TResult extends DataType = DataType,
  TParameters = unknown,
> {
  public parameters: TParameters
  public dataType: DataType

  constructor(parameters: TParameters, dataType: TResult) {
    this.parameters = parameters
    this.dataType = dataType
  }

  abstract decode(
    slice: CramSlice,
    coreDataBlock: CramFileBlock,
    blocksByContentId: Record<number, CramFileBlock>,
    cursors: Cursors,
  ): DataTypeMapping[TResult]

  getBytesSubarray(
    _blocksByContentId: Record<number, CramFileBlock>,
    _cursors: Cursors,
    _length: number,
  ): Uint8Array | undefined {
    return undefined
  }
}
