from __future__ import annotations from app.repositories.scheme_groups import list_scheme_version_groups from app.repositories.scheme_seats import list_scheme_version_seats from app.repositories.scheme_sectors import list_scheme_version_sectors from app.services.baseline_selector import select_baseline_scheme_version def _serialize_sector(row) -> dict: return { "sector_record_id": row.sector_record_id, "element_id": row.element_id, "sector_id": row.sector_id, "name": row.name, "classes_raw": row.classes_raw, } def _serialize_group(row) -> dict: return { "group_record_id": row.group_record_id, "element_id": row.element_id, "group_id": row.group_id, "name": row.name, "classes_raw": row.classes_raw, } def _serialize_seat(row) -> dict: return { "seat_record_id": row.seat_record_id, "element_id": row.element_id, "seat_id": row.seat_id, "sector_id": row.sector_id, "group_id": row.group_id, "row_label": row.row_label, "seat_number": row.seat_number, } def _build_diff(before_map: dict, after_map: dict) -> list[dict]: keys = sorted(set(before_map.keys()) | set(after_map.keys())) result: list[dict] = [] for key in keys: before = before_map.get(key) after = after_map.get(key) if before is None and after is not None: status = "added" elif before is not None and after is None: status = "removed" elif before != after: status = "changed" else: status = "unchanged" result.append( { "key": key, "status": status, "before": before, "after": after, } ) return result async def build_structure_diff( *, scheme_id: str, draft_scheme_version_id: str, baseline_override_scheme_version_id: str | None = None, ) -> dict: baseline, baseline_strategy = await select_baseline_scheme_version( scheme_id=scheme_id, draft_scheme_version_id=draft_scheme_version_id, override_scheme_version_id=baseline_override_scheme_version_id, ) draft_sectors = await list_scheme_version_sectors(draft_scheme_version_id) draft_groups = await list_scheme_version_groups(draft_scheme_version_id) draft_seats = await list_scheme_version_seats(draft_scheme_version_id) if baseline is None: baseline_sector_map = {} baseline_group_map = {} baseline_seat_map = {} baseline_scheme_version_id = None else: baseline_scheme_version_id = baseline.scheme_version_id baseline_sector_map = { row.sector_record_id: _serialize_sector(row) for row in await list_scheme_version_sectors(baseline.scheme_version_id) } baseline_group_map = { row.group_record_id: _serialize_group(row) for row in await list_scheme_version_groups(baseline.scheme_version_id) } baseline_seat_map = { row.seat_record_id: _serialize_seat(row) for row in await list_scheme_version_seats(baseline.scheme_version_id) } draft_sector_map = {row.sector_record_id: _serialize_sector(row) for row in draft_sectors} draft_group_map = {row.group_record_id: _serialize_group(row) for row in draft_groups} draft_seat_map = {row.seat_record_id: _serialize_seat(row) for row in draft_seats} sector_diff = _build_diff(baseline_sector_map, draft_sector_map) group_diff = _build_diff(baseline_group_map, draft_group_map) seat_diff = _build_diff(baseline_seat_map, draft_seat_map) return { "baseline_scheme_version_id": baseline_scheme_version_id, "baseline_strategy": baseline_strategy, "summary": { "sectors_added": sum(1 for item in sector_diff if item["status"] == "added"), "sectors_removed": sum(1 for item in sector_diff if item["status"] == "removed"), "sectors_changed": sum(1 for item in sector_diff if item["status"] == "changed"), "groups_added": sum(1 for item in group_diff if item["status"] == "added"), "groups_removed": sum(1 for item in group_diff if item["status"] == "removed"), "groups_changed": sum(1 for item in group_diff if item["status"] == "changed"), "seats_added": sum(1 for item in seat_diff if item["status"] == "added"), "seats_removed": sum(1 for item in seat_diff if item["status"] == "removed"), "seats_changed": sum(1 for item in seat_diff if item["status"] == "changed"), }, "sectors": sector_diff, "groups": group_diff, "seats": seat_diff, }