"""Excel (.xlsx) file operations via openpyxl."""

import os

from fliiq.runtime.security import check_path_allowed

MAX_READ_ROWS = 10_000


async def handler(params: dict) -> dict:
    """Handle Excel operations."""
    action = params["action"]

    if action == "create":
        return _create(params)
    elif action == "read":
        return _read(params)
    elif action == "write":
        return _write(params)
    elif action == "list_sheets":
        return _list_sheets(params)
    elif action == "add_sheet":
        return _add_sheet(params)
    elif action == "delete":
        return _delete(params)
    else:
        raise ValueError(f"Unknown action: {action}")


def _require_path(params: dict) -> str:
    path = params.get("path")
    if not path:
        raise ValueError("'path' is required")
    check_path_allowed(path)
    return path


def _create(params: dict) -> dict:
    """Create a new .xlsx workbook."""
    import openpyxl

    path = _require_path(params)
    data = params.get("data")
    sheet_name = params.get("sheet", "Sheet1")

    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = sheet_name

    if data:
        for row in data:
            ws.append(row)

    parent = os.path.dirname(path)
    if parent:
        os.makedirs(parent, exist_ok=True)
    wb.save(path)

    row_count = len(data) if data else 0
    return {
        "success": True,
        "message": f"Created {path} with {row_count} row(s) on '{sheet_name}'",
        "data": {"path": path, "sheet": sheet_name, "rows": row_count},
    }


def _read(params: dict) -> dict:
    """Read data from a sheet."""
    import openpyxl

    path = _require_path(params)
    if not os.path.isfile(path):
        raise FileNotFoundError(f"File not found: {path}")

    wb = openpyxl.load_workbook(path, read_only=True, data_only=True)
    sheet_name = params.get("sheet")
    ws = wb[sheet_name] if sheet_name and sheet_name in wb.sheetnames else wb.active

    cell_range = params.get("range")

    rows = []
    if cell_range:
        for row in ws[cell_range]:
            rows.append([cell.value for cell in row])
    else:
        for row in ws.iter_rows(values_only=True):
            rows.append(list(row))
            if len(rows) >= MAX_READ_ROWS:
                break

    wb.close()

    truncated = len(rows) >= MAX_READ_ROWS
    return {
        "success": True,
        "message": f"Read {len(rows)} row(s) from '{ws.title}'" + (" (truncated)" if truncated else ""),
        "data": {
            "sheet": ws.title,
            "rows": len(rows),
            "values": rows,
            "truncated": truncated,
        },
    }


def _write(params: dict) -> dict:
    """Write data to cells."""
    import openpyxl
    from openpyxl.utils import coordinate_to_tuple

    path = _require_path(params)
    data = params.get("data")
    if not data:
        raise ValueError("'data' is required for write")

    if os.path.isfile(path):
        wb = openpyxl.load_workbook(path)
    else:
        parent = os.path.dirname(path)
        if parent:
            os.makedirs(parent, exist_ok=True)
        wb = openpyxl.Workbook()

    sheet_name = params.get("sheet")
    if sheet_name and sheet_name in wb.sheetnames:
        ws = wb[sheet_name]
    elif sheet_name:
        ws = wb.create_sheet(sheet_name)
    else:
        ws = wb.active

    start_cell = params.get("start_cell", "A1")
    start_row, start_col = coordinate_to_tuple(start_cell)

    for r_idx, row in enumerate(data):
        for c_idx, value in enumerate(row):
            ws.cell(row=start_row + r_idx, column=start_col + c_idx, value=value)

    wb.save(path)

    total_cells = sum(len(row) for row in data)
    return {
        "success": True,
        "message": f"Wrote {total_cells} cell(s) to '{ws.title}' starting at {start_cell}",
        "data": {
            "path": path,
            "sheet": ws.title,
            "cells_written": total_cells,
            "rows": len(data),
        },
    }


def _list_sheets(params: dict) -> dict:
    """List sheet names."""
    import openpyxl

    path = _require_path(params)
    if not os.path.isfile(path):
        raise FileNotFoundError(f"File not found: {path}")

    wb = openpyxl.load_workbook(path, read_only=True)
    names = wb.sheetnames
    wb.close()

    return {
        "success": True,
        "message": f"{len(names)} sheet(s) in {path}",
        "data": {"sheets": names},
    }


def _add_sheet(params: dict) -> dict:
    """Add a new sheet."""
    import openpyxl

    path = _require_path(params)
    if not os.path.isfile(path):
        raise FileNotFoundError(f"File not found: {path}")

    title = params.get("title", "Sheet")

    wb = openpyxl.load_workbook(path)
    if title in wb.sheetnames:
        raise ValueError(f"Sheet '{title}' already exists in {path}")
    wb.create_sheet(title)
    wb.save(path)

    return {
        "success": True,
        "message": f"Added sheet '{title}' to {path}",
        "data": {"path": path, "sheet": title, "total_sheets": len(wb.sheetnames)},
    }


def _delete(params: dict) -> dict:
    """Delete an .xlsx file."""
    path = _require_path(params)
    if not os.path.isfile(path):
        raise FileNotFoundError(f"File not found: {path}")
    os.remove(path)
    return {
        "success": True,
        "message": f"Deleted {path}",
        "data": {"deleted": path},
    }
