"""Evidence pack generation with manifests and signatures."""

import io
from typing import Any

import structlog

logger = structlog.get_logger()


class EvidencePackGenerator:  # pylint: disable=too-few-public-methods
    """Generate evidence packs with manifests and signatures"""

    def __init__(self, storage_client: Any) -> None:
        self.storage = storage_client

    async def create_evidence_pack(  # pylint: disable=too-many-locals
        self,
        taxpayer_id: str,
        tax_year: str,
        scope: str,
        evidence_items: list[dict[str, Any]],
    ) -> dict[str, Any]:
        """Create evidence pack with manifest and signatures"""
        # pylint: disable=import-outside-toplevel
        import hashlib
        import json
        import zipfile
        from datetime import datetime

        try:
            # Create ZIP buffer
            zip_buffer = io.BytesIO()

            with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file:
                manifest: dict[str, Any] = {
                    "taxpayer_id": taxpayer_id,
                    "tax_year": tax_year,
                    "scope": scope,
                    "created_at": datetime.utcnow().isoformat(),
                    "evidence_items": [],
                    "signatures": {},
                }

                # Add evidence files to ZIP
                for item in evidence_items:
                    doc_id = item["doc_id"]
                    page = item.get("page")
                    bbox = item.get("bbox")
                    text_hash = item.get("text_hash")

                    # Get document content
                    doc_content = await self.storage.get_object(
                        bucket_name="raw-documents",
                        object_name=f"tenants/{taxpayer_id}/raw/{doc_id}.pdf",
                    )

                    if doc_content:
                        # Add to ZIP
                        zip_filename = f"documents/{doc_id}.pdf"
                        zip_file.writestr(zip_filename, doc_content)

                        # Calculate file hash
                        file_hash = hashlib.sha256(doc_content).hexdigest()

                        # Add to manifest
                        manifest["evidence_items"].append(
                            {
                                "doc_id": doc_id,
                                "filename": zip_filename,
                                "page": page,
                                "bbox": bbox,
                                "text_hash": text_hash,
                                "file_hash": file_hash,
                                "file_size": len(doc_content),
                            }
                        )

                # Sign manifest
                manifest_json = json.dumps(manifest, indent=2, sort_keys=True)
                manifest_hash = hashlib.sha256(manifest_json.encode()).hexdigest()

                manifest["signatures"]["manifest_hash"] = manifest_hash
                manifest["signatures"]["algorithm"] = "SHA-256"

                # Add manifest to ZIP
                zip_file.writestr("manifest.json", json.dumps(manifest, indent=2))

            # Get ZIP content
            zip_content = zip_buffer.getvalue()

            # Store evidence pack
            pack_filename = f"evidence_pack_{taxpayer_id}_{tax_year}_{scope}.zip"
            pack_key = f"tenants/{taxpayer_id}/evidence_packs/{pack_filename}"

            success = await self.storage.put_object(
                bucket_name="evidence-packs",
                object_name=pack_key,
                data=io.BytesIO(zip_content),
                length=len(zip_content),
                content_type="application/zip",
            )

            if success:
                return {
                    "pack_filename": pack_filename,
                    "pack_key": pack_key,
                    "pack_size": len(zip_content),
                    "evidence_count": len(evidence_items),
                    "manifest_hash": manifest_hash,
                    "s3_url": f"s3://evidence-packs/{pack_key}",
                }
            raise RuntimeError("Failed to store evidence pack")

        except Exception as e:  # pylint: disable=broad-exception-caught
            logger.error("Failed to create evidence pack", error=str(e))
            raise


# Form configuration for UK tax forms
UK_TAX_FORMS = {
    "SA100": {
        "name": "Self Assessment Tax Return",
        "template_path": "forms/templates/SA100.pdf",
        "boxes": {
            "1": {"description": "Your name", "type": "text"},
            "2": {"description": "Your address", "type": "text"},
            "3": {"description": "Your UTR", "type": "text"},
            "4": {"description": "Your NI number", "type": "text"},
        },
    },
    "SA103": {
        "name": "Self-employment (full)",
        "template_path": "forms/templates/SA103.pdf",
        "boxes": {
            "1": {"description": "Business name", "type": "text"},
            "2": {"description": "Business description", "type": "text"},
            "3": {"description": "Accounting period start", "type": "date"},
            "4": {"description": "Accounting period end", "type": "date"},
            "20": {"description": "Total turnover", "type": "currency"},
            "31": {
                "description": "Total allowable business expenses",
                "type": "currency",
            },
            "32": {"description": "Net profit", "type": "currency"},
            "33": {"description": "Balancing charges", "type": "currency"},
            "34": {"description": "Goods/services for own use", "type": "currency"},
            "35": {"description": "Total taxable profits", "type": "currency"},
        },
    },
    "SA105": {
        "name": "Property income",
        "template_path": "forms/templates/SA105.pdf",
        "boxes": {
            "20": {"description": "Total rents and other income", "type": "currency"},
            "29": {
                "description": "Premiums for the grant of a lease",
                "type": "currency",
            },
            "31": {
                "description": "Rent, rates, insurance, ground rents etc",
                "type": "currency",
            },
            "32": {"description": "Property management", "type": "currency"},
            "33": {
                "description": "Services provided, including wages",
                "type": "currency",
            },
            "34": {
                "description": "Repairs, maintenance and renewals",
                "type": "currency",
            },
            "35": {
                "description": "Finance costs, including interest",
                "type": "currency",
            },
            "36": {"description": "Professional fees", "type": "currency"},
            "37": {"description": "Costs of services provided", "type": "currency"},
            "38": {
                "description": "Other allowable property expenses",
                "type": "currency",
            },
        },
    },
}
