/**
 * Style-side table property parsers.
 *
 * Parse the w:tblPr / w:trPr / w:tcPr that appear *inside* `<w:style>`
 * definitions in styles.xml. Mirrors the document-side parsers in
 * `../tableParser.ts` — the two paths feed different cascades and the
 * duplication is intentional.
 */

import type {
  Theme,
  TableFormatting,
  TableRowFormatting,
  TableCellFormatting,
  TableBorders,
  CellMargins,
  TableLook,
  TableMeasurement,
} from '../../types/document';
import {
  findChild,
  getAttribute,
  parseBooleanElement,
  parseNumericAttribute,
  type XmlElement,
} from '../xmlParser';
import { parseShadingProperties } from './runProperties';
import { parseBorderSpec } from './paragraphProperties';

/**
 * Parse table measurement (width/height with type)
 */
function parseTableMeasurement(element: XmlElement | null): TableMeasurement | undefined {
  if (!element) return undefined;

  const w = parseNumericAttribute(element, 'w', 'w');
  const type = getAttribute(element, 'w', 'type');

  if (w !== undefined && type) {
    return {
      value: w,
      type: type as TableMeasurement['type'],
    };
  }

  return undefined;
}

/**
 * Parse table borders
 */
function parseTableBorders(tblBorders: XmlElement | null): TableBorders | undefined {
  if (!tblBorders) return undefined;

  const borders: TableBorders = {};

  const top = parseBorderSpec(findChild(tblBorders, 'w', 'top'));
  if (top) borders.top = top;

  const bottom = parseBorderSpec(findChild(tblBorders, 'w', 'bottom'));
  if (bottom) borders.bottom = bottom;

  const left = parseBorderSpec(findChild(tblBorders, 'w', 'left'));
  if (left) borders.left = left;

  const right = parseBorderSpec(findChild(tblBorders, 'w', 'right'));
  if (right) borders.right = right;

  const insideH = parseBorderSpec(findChild(tblBorders, 'w', 'insideH'));
  if (insideH) borders.insideH = insideH;

  const insideV = parseBorderSpec(findChild(tblBorders, 'w', 'insideV'));
  if (insideV) borders.insideV = insideV;

  return Object.keys(borders).length > 0 ? borders : undefined;
}

/**
 * Parse cell margins
 */
function parseCellMargins(tblCellMar: XmlElement | null): CellMargins | undefined {
  if (!tblCellMar) return undefined;

  const margins: CellMargins = {};

  const top = parseTableMeasurement(findChild(tblCellMar, 'w', 'top'));
  if (top) margins.top = top;

  const bottom = parseTableMeasurement(findChild(tblCellMar, 'w', 'bottom'));
  if (bottom) margins.bottom = bottom;

  const left = parseTableMeasurement(findChild(tblCellMar, 'w', 'left'));
  if (left) margins.left = left;

  const right = parseTableMeasurement(findChild(tblCellMar, 'w', 'right'));
  if (right) margins.right = right;

  return Object.keys(margins).length > 0 ? margins : undefined;
}

/**
 * Parse table look flags
 */
function parseTableLook(tblLook: XmlElement | null): TableLook | undefined {
  if (!tblLook) return undefined;

  const look: TableLook = {};

  // Can be specified as individual attributes or a single val attribute
  const val = getAttribute(tblLook, 'w', 'val');
  if (val) {
    // val is a hex bitmap: bit 0=firstRow, 1=lastRow, 2=firstCol, 3=lastCol, 4=noHBand, 5=noVBand
    const num = parseInt(val, 16);
    if (!isNaN(num)) {
      look.firstRow = (num & 0x0020) !== 0;
      look.lastRow = (num & 0x0040) !== 0;
      look.firstColumn = (num & 0x0080) !== 0;
      look.lastColumn = (num & 0x0100) !== 0;
      look.noHBand = (num & 0x0200) !== 0;
      look.noVBand = (num & 0x0400) !== 0;
    }
  }

  // Individual attributes override
  const firstColumn = getAttribute(tblLook, 'w', 'firstColumn');
  if (firstColumn) look.firstColumn = firstColumn === '1';

  const firstRow = getAttribute(tblLook, 'w', 'firstRow');
  if (firstRow) look.firstRow = firstRow === '1';

  const lastColumn = getAttribute(tblLook, 'w', 'lastColumn');
  if (lastColumn) look.lastColumn = lastColumn === '1';

  const lastRow = getAttribute(tblLook, 'w', 'lastRow');
  if (lastRow) look.lastRow = lastRow === '1';

  const noHBand = getAttribute(tblLook, 'w', 'noHBand');
  if (noHBand) look.noHBand = noHBand === '1';

  const noVBand = getAttribute(tblLook, 'w', 'noVBand');
  if (noVBand) look.noVBand = noVBand === '1';

  return Object.keys(look).length > 0 ? look : undefined;
}

/**
 * Parse table formatting properties (w:tblPr)
 */
export function parseTableProperties(
  tblPr: XmlElement | null,
  _theme: Theme | null
): TableFormatting | undefined {
  if (!tblPr) return undefined;

  const formatting: TableFormatting = {};

  // Table width
  const tblW = findChild(tblPr, 'w', 'tblW');
  if (tblW) {
    formatting.width = parseTableMeasurement(tblW);
  }

  // Table alignment/justification
  const jc = findChild(tblPr, 'w', 'jc');
  if (jc) {
    const val = getAttribute(jc, 'w', 'val');
    if (val === 'left' || val === 'center' || val === 'right') {
      formatting.justification = val;
    }
  }

  // Cell spacing
  const tblCellSpacing = findChild(tblPr, 'w', 'tblCellSpacing');
  if (tblCellSpacing) {
    formatting.cellSpacing = parseTableMeasurement(tblCellSpacing);
  }

  // Table indent
  const tblInd = findChild(tblPr, 'w', 'tblInd');
  if (tblInd) {
    formatting.indent = parseTableMeasurement(tblInd);
  }

  // Table borders
  const tblBorders = findChild(tblPr, 'w', 'tblBorders');
  if (tblBorders) {
    formatting.borders = parseTableBorders(tblBorders);
  }

  // Cell margins
  const tblCellMar = findChild(tblPr, 'w', 'tblCellMar');
  if (tblCellMar) {
    formatting.cellMargins = parseCellMargins(tblCellMar);
  }

  // Table layout
  const tblLayout = findChild(tblPr, 'w', 'tblLayout');
  if (tblLayout) {
    const val = getAttribute(tblLayout, 'w', 'type');
    if (val === 'fixed' || val === 'autofit') {
      formatting.layout = val;
    }
  }

  // Table style
  const tblStyle = findChild(tblPr, 'w', 'tblStyle');
  if (tblStyle) {
    const val = getAttribute(tblStyle, 'w', 'val');
    if (val) formatting.styleId = val;
  }

  // Table look
  const tblLook = findChild(tblPr, 'w', 'tblLook');
  if (tblLook) {
    formatting.look = parseTableLook(tblLook);
  }

  // Shading
  const shd = findChild(tblPr, 'w', 'shd');
  if (shd) {
    formatting.shading = parseShadingProperties(shd);
  }

  // Bidi
  const bidiVisual = findChild(tblPr, 'w', 'bidiVisual');
  if (bidiVisual) formatting.bidi = parseBooleanElement(bidiVisual);

  return Object.keys(formatting).length > 0 ? formatting : undefined;
}

/**
 * Parse table row formatting properties (w:trPr)
 */
export function parseTableRowProperties(trPr: XmlElement | null): TableRowFormatting | undefined {
  if (!trPr) return undefined;

  const formatting: TableRowFormatting = {};

  // Row height
  const trHeight = findChild(trPr, 'w', 'trHeight');
  if (trHeight) {
    formatting.height = parseTableMeasurement(trHeight);
    const hRule = getAttribute(trHeight, 'w', 'hRule');
    if (hRule) {
      formatting.heightRule = hRule as TableRowFormatting['heightRule'];
    }
  }

  // Header row
  const tblHeader = findChild(trPr, 'w', 'tblHeader');
  if (tblHeader) formatting.header = parseBooleanElement(tblHeader);

  // Can't split
  const cantSplit = findChild(trPr, 'w', 'cantSplit');
  if (cantSplit) formatting.cantSplit = parseBooleanElement(cantSplit);

  // Row justification
  const jc = findChild(trPr, 'w', 'jc');
  if (jc) {
    const val = getAttribute(jc, 'w', 'val');
    if (val === 'left' || val === 'center' || val === 'right') {
      formatting.justification = val;
    }
  }

  // Hidden
  const hidden = findChild(trPr, 'w', 'hidden');
  if (hidden) formatting.hidden = parseBooleanElement(hidden);

  return Object.keys(formatting).length > 0 ? formatting : undefined;
}

/**
 * Parse table cell formatting properties (w:tcPr)
 */
export function parseTableCellProperties(
  tcPr: XmlElement | null,
  _theme: Theme | null
): TableCellFormatting | undefined {
  if (!tcPr) return undefined;

  const formatting: TableCellFormatting = {};

  // Cell width
  const tcW = findChild(tcPr, 'w', 'tcW');
  if (tcW) {
    formatting.width = parseTableMeasurement(tcW);
  }

  // Cell borders
  const tcBorders = findChild(tcPr, 'w', 'tcBorders');
  if (tcBorders) {
    formatting.borders = parseTableBorders(tcBorders);
  }

  // Cell margins
  const tcMar = findChild(tcPr, 'w', 'tcMar');
  if (tcMar) {
    formatting.margins = parseCellMargins(tcMar);
  }

  // Shading
  const shd = findChild(tcPr, 'w', 'shd');
  if (shd) {
    formatting.shading = parseShadingProperties(shd);
  }

  // Vertical alignment
  const vAlign = findChild(tcPr, 'w', 'vAlign');
  if (vAlign) {
    const val = getAttribute(vAlign, 'w', 'val');
    if (val === 'top' || val === 'center' || val === 'bottom') {
      formatting.verticalAlign = val;
    }
  }

  // Text direction
  const textDirection = findChild(tcPr, 'w', 'textDirection');
  if (textDirection) {
    const val = getAttribute(textDirection, 'w', 'val');
    if (val) formatting.textDirection = val as TableCellFormatting['textDirection'];
  }

  // Grid span (horizontal merge)
  const gridSpan = findChild(tcPr, 'w', 'gridSpan');
  if (gridSpan) {
    const val = parseNumericAttribute(gridSpan, 'w', 'val');
    if (val !== undefined) formatting.gridSpan = val;
  }

  // Vertical merge
  const vMerge = findChild(tcPr, 'w', 'vMerge');
  if (vMerge) {
    const val = getAttribute(vMerge, 'w', 'val');
    formatting.vMerge = val === 'restart' ? 'restart' : 'continue';
  }

  // Fit text
  const tcFitText = findChild(tcPr, 'w', 'tcFitText');
  if (tcFitText) formatting.fitText = parseBooleanElement(tcFitText);

  // No wrap
  const noWrap = findChild(tcPr, 'w', 'noWrap');
  if (noWrap) formatting.noWrap = parseBooleanElement(noWrap);

  // Hide mark
  const hideMark = findChild(tcPr, 'w', 'hideMark');
  if (hideMark) formatting.hideMark = parseBooleanElement(hideMark);

  return Object.keys(formatting).length > 0 ? formatting : undefined;
}
