"""Markdown table formatter for dlist"""

from .table import TableFormatter
from ..helpers import chars


class MarkdownFormatter(TableFormatter):
    """Markdown table formatter

    Produces pipe-delimited tables compatible with GitHub, GitLab,
    Obsidian, and most Markdown renderers.  Categories become ``#``
    headings (level increases with depth).

    Access via ``get_formatter('md')`` or ``Dlist.write(format='md')``.

    Parameters (passed as **kwargs to ``format`` / ``format_categorized``)::

        keys      – list of column keys to display
        titles    – {key: display_name} for column headers;
                    for categories: {cat_key: format_string} e.g. 'Type: {}'
        width     – int: fixed column width (values truncated with …)
                    'auto': each column sized to its widest value
        maxwidth  – int: cap for auto-width (0 = no cap)
        nCols     – number of column groups side by side (default: 1)
        page      – rows per page; 0 = no pagination (default: 0)
        blank     – placeholder for missing values (default: '&nbsp;')
        align     – 'left' (default), 'right', or 'center'

    **Basic table**::

        >>> fmt = get_formatter('md')
        >>> print(fmt.format(d, keys=['id', 'name', 'type'], width=10))
        |id          |name        |type      |
        |:-----------|:-----------|:---------|
        |E0001       |Sintel      |E         |
        |E0002       |arroyito    |E         |

    **Auto-width**::

        >>> print(fmt.format(d, keys=['id', 'name'], width='auto'))
        |id   |name    |
        |:----|:-------|
        |E0001|Sintel  |
        |E0002|arroyito|

    **Multi-column**::

        >>> print(fmt.format(d, keys=['id', 'name'], nCols=2, width=10))
        |id          |name        ||id          |name        |
        |:-----------|:-----------||:-----------|:-----------|
        |E0001       |Sintel      ||E0002       |arroyito    |

    **Categorized** (headings)::

        >>> print(fmt.format_categorized(d, ['type', 'dir'], ['id', 'name'],
        ...       titles={'type': 'Type: {}', 'dir': '{}'}))
        # Type: A
        ## /flaw/
        |id            |name        |
        |:-------------|:-----------|
        |E0004         |test_4      |

        ## /test/
        ...

        # Type: E
        ...

    **Via Dlist methods**::

        >>> d.write(format='md', keys=['id', 'name'], width='auto')
        >>> d.write_categorized(['type'], ['id', 'name'], format='md')
    """

    def _skin(self, **kwargs):
        return {
            'sep': '|',
            'sepCol': '|' + chars.Vl + '|',
            'start': '|',
            'lstart': None,
            'end': '|',
            'blank': '&nbsp;',
            'width': 'auto',
            'nCols': 1,
            'page': 0,
            'maxwidth': 0,
            'align': 'left',
        }

    def _col_widths(self, keys, fmt):
        """Get per-key widths (auto or uniform)."""
        cw = fmt.get('_col_widths')
        if cw:
            return cw
        w = fmt['width'] if isinstance(fmt['width'], int) else 1
        return {k: w for k in keys}

    def _hline(self, keys, fmt, pos='mid'):
        # Markdown only has the separator row under the header
        if pos != 'mid' or not keys:
            return ''
        nCols = fmt['nCols']
        align = fmt.get('align', 'left')
        cw = self._col_widths(keys, fmt)

        def _sep_cell(k):
            w = cw[k]
            if align == 'center':
                return ':' + '-' * (w - 2) + ':'
            elif align == 'right':
                return '-' * (w - 1) + ':'
            else:
                return ':' + '-' * (w - 1)

        cells = [_sep_cell(k) for k in keys]
        group = '|'.join(cells)
        if nCols <= 1:
            return '|' + group + '|'
        sep_col = '|' + '-' + '|'
        return '|' + sep_col.join([group] * nCols) + '|'

    def _header(self, keys, titles, fmt):
        if not keys:
            return ''
        nCols = fmt['nCols']
        cw = self._col_widths(keys, fmt)

        cells = [f'{{:{cw[k]}s}}'.format(titles.get(k, k)) for k in keys]
        group = '|'.join(cells)
        if nCols <= 1:
            return '|' + group + '|'
        sep_col = '|' + chars.Vl + '|'
        return '|' + sep_col.join([group] * nCols) + '|'

    def _paginate(self, row_lines, keys, titles, fmt):
        """Join pages with ``&nbsp;`` for visible spacing in Markdown."""
        header = self._header(keys, titles, fmt)
        hl_mid = self._hline(keys, fmt, pos='mid')
        page = fmt.get('page', 0)

        def _block(chunk):
            parts = []
            if header:
                parts.append(header)
                if hl_mid:
                    parts.append(hl_mid)
            parts.extend(chunk)
            return '\n'.join(parts)

        if not page or page <= 0:
            return _block(row_lines)

        blocks = []
        for i in range(0, len(row_lines), page):
            blocks.append(_block(row_lines[i:i + page]))
        return '\n\n&nbsp;\n'.join(blocks)

    # ── Categorized ──────────────────────────────────────────────────

    def _cat_prefix(self, label, level, depth, is_last, fmt, is_first=False):
        """Categories as markdown headings: # for level 0, ## for level 1, etc."""
        hashes = '#' * (level + 1)
        prefix = '\n' if level == 0 else ''
        return f'{prefix}{hashes} {label}'

    def _cat_indent(self, level, total_depth, is_last, fmt):
        # No indent in markdown — tables are at root level
        return ''

    def format_categorized(self, dlist, ctree, keys, titles={}, **kwargs):
        # Default to auto-width for categorized markdown
        if 'width' not in kwargs:
            kwargs['width'] = 'auto'
        result = super().format_categorized(dlist, ctree, keys, titles=titles,
                                            **kwargs)
        # Strip leading blank line from first category
        if result.startswith('\n'):
            result = result[1:]
        return result
