"""Workbook build adapter and recoverable atomic publication."""

from __future__ import annotations

import hashlib
import json
import os
import shutil
import tempfile
import uuid
from dataclasses import dataclass
from datetime import date, datetime
from pathlib import Path
from typing import Any, Dict, Mapping, Optional, Tuple

from openpyxl import Workbook, load_workbook
from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
from openpyxl.worksheet.worksheet import Worksheet

from arr_storage.store import ManagedObjectStore
from company_reports.contracts import CompanyReport, ErrorCode, RESULT_SCHEMA_VERSION
from company_reports.repository import (
    FileMetadata,
    ReportRepository,
    RepositoryError,
    ReservedReport,
)


XLSX_MIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
REPORT_HEADERS = (
    "ARRIVAL",
    "DEPARTURE",
    "NIGHTS",
    "BLOCK_CODE",
    "RES_COMMENT",
    "Booking Room",
    "Total Booking Price",
)
BODY_FONT = "222222"
DUPLICATE_FILL = "FFF2CC"
DUPLICATE_FONT = "9C6500"
REVIEW_FILL = "FCE4D6"
REVIEW_FONT = "C65911"
HEADER_FILL = "FFFFFF"


class BuildError(RuntimeError):
    def __init__(self, code: str, safe_message: str):
        super().__init__(safe_message)
        self.code = code
        self.safe_message = safe_message


class PublicationError(RuntimeError):
    def __init__(self, code: str, safe_message: str):
        super().__init__(safe_message)
        self.code = code
        self.safe_message = safe_message


@dataclass(frozen=True)
class BuiltWorkbook:
    path: Path
    sha256: str
    byte_size: int
    summary: Mapping[str, Any]


@dataclass(frozen=True)
class PublicationOutcome:
    current_path: Path
    archive_path: Path
    result_path: Path
    artifact: FileMetadata
    result_json: FileMetadata


def sha256_file(path: Path) -> str:
    digest = hashlib.sha256()
    with path.open("rb") as handle:
        for chunk in iter(lambda: handle.read(1024 * 1024), b""):
            digest.update(chunk)
    return digest.hexdigest()


def _private_json(path: Path, payload: Mapping[str, Any]) -> None:
    path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
    descriptor = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
    try:
        with os.fdopen(descriptor, "w", encoding="utf-8") as handle:
            json.dump(payload, handle, ensure_ascii=False, sort_keys=True, indent=2)
            handle.write("\n")
            handle.flush()
            os.fsync(handle.fileno())
    except Exception:
        try:
            os.close(descriptor)
        except OSError:
            pass
        raise


class OpenpyxlWorkbookBuilder:
    def __init__(self, *_legacy_args: Any, **_legacy_options: Any) -> None:
        # Retain import/call compatibility for older wrappers; no external
        # workbook runtime is consulted.
        _ = (_legacy_args, _legacy_options)

    @staticmethod
    def _safe_text(value: Any) -> str:
        text = str(value or "")
        return "'" + text if text[:1] in {"=", "+", "-", "@"} else text

    @staticmethod
    def _date_key(value: Any) -> str:
        if isinstance(value, datetime):
            return value.date().isoformat()
        if isinstance(value, date):
            return value.isoformat()
        if isinstance(value, str) and len(value) >= 10:
            return value[:10]
        return ""

    @staticmethod
    def _cell_text(value: Any) -> str:
        return "" if value is None else str(value)

    @staticmethod
    def _semantic_sha256(payload: Mapping[str, Any]) -> str:
        encoded = json.dumps(
            {
                "headers": payload["headers"],
                "periods": payload["periods"],
            },
            ensure_ascii=False,
            separators=(",", ":"),
        ).encode("utf-8")
        return hashlib.sha256(encoded).hexdigest()

    def _write_sheet(
        self,
        worksheet: Worksheet,
        period: Any,
    ) -> None:
        worksheet.append(list(REPORT_HEADERS))
        for row in period.rows:
            worksheet.append(
                [
                    row.arrival,
                    row.departure,
                    row.nights,
                    self._safe_text(row.block_code),
                    self._safe_text(row.res_comment),
                    self._safe_text(row.booking_room),
                    self._safe_text(row.total_booking_price),
                ]
            )

        worksheet.column_dimensions["A"].width = 13
        worksheet.column_dimensions["B"].width = 13
        worksheet.column_dimensions["C"].width = 9
        worksheet.column_dimensions["D"].width = 20
        worksheet.column_dimensions["E"].width = 25
        worksheet.column_dimensions["F"].width = 34
        worksheet.column_dimensions["G"].width = 48
        worksheet.freeze_panes = "A2"
        worksheet.auto_filter.ref = f"A1:G{max(1, worksheet.max_row)}"

        thin_bottom = Border(
            bottom=Side(style="thin", color="7F7F7F"),
        )
        header_fill = PatternFill("solid", fgColor=HEADER_FILL)
        duplicate_fill = PatternFill("solid", fgColor=DUPLICATE_FILL)
        review_fill = PatternFill("solid", fgColor=REVIEW_FILL)
        for cell in worksheet[1]:
            cell.fill = header_fill
            cell.font = Font(name="Arial", size=10, bold=True, color="000000")
            cell.alignment = Alignment(horizontal="center", vertical="center")
            cell.border = thin_bottom
        worksheet.row_dimensions[1].height = 24

        for row_index in range(2, worksheet.max_row + 1):
            worksheet.row_dimensions[row_index].height = 30
            for cell in worksheet[row_index]:
                cell.font = Font(name="Arial", size=10, color=BODY_FONT)
                cell.alignment = Alignment(vertical="center")
            for column in ("A", "B", "C", "D"):
                worksheet[f"{column}{row_index}"].alignment = Alignment(
                    horizontal="center",
                    vertical="center",
                )
            for column in ("E", "F", "G"):
                worksheet[f"{column}{row_index}"].alignment = Alignment(
                    horizontal="left",
                    vertical="center",
                    wrap_text=True,
                )
            worksheet[f"A{row_index}"].number_format = "yyyy-mm-dd"
            worksheet[f"B{row_index}"].number_format = "yyyy-mm-dd"

        for offset, source_row in enumerate(period.rows, start=2):
            if source_row.duplicate_group:
                for column in range(1, 8):
                    worksheet.cell(offset, column).fill = duplicate_fill
                worksheet[f"E{offset}"].font = Font(
                    name="Arial",
                    size=10,
                    bold=True,
                    color=DUPLICATE_FONT,
                )
            if source_row.multi_price_review:
                worksheet[f"G{offset}"].fill = review_fill
                worksheet[f"G{offset}"].font = Font(
                    name="Arial",
                    size=10,
                    bold=True,
                    color=REVIEW_FONT,
                )

    def _validate_workbook(self, output_path: Path, report: CompanyReport) -> int:
        workbook = load_workbook(output_path, data_only=False)
        expected_names = [period.sheet_name for period in report.periods]
        if workbook.sheetnames != expected_names:
            raise ValueError("worksheet names do not match")
        formula_count = 0
        for period in report.periods:
            worksheet = workbook[period.sheet_name]
            expected_rows = len(period.rows) + 1
            if worksheet.max_row != expected_rows or worksheet.max_column != 7:
                raise ValueError("worksheet dimensions do not match")
            headers = [worksheet.cell(1, column).value for column in range(1, 8)]
            if headers != list(REPORT_HEADERS):
                raise ValueError("worksheet headers do not match")
            for row_index, row in enumerate(period.rows, start=2):
                expected = [
                    row.arrival.isoformat(),
                    row.departure.isoformat(),
                    row.nights,
                    self._safe_text(row.block_code),
                    self._safe_text(row.res_comment),
                    self._safe_text(row.booking_room),
                    self._safe_text(row.total_booking_price),
                ]
                actual = [
                    self._date_key(worksheet.cell(row_index, 1).value),
                    self._date_key(worksheet.cell(row_index, 2).value),
                    worksheet.cell(row_index, 3).value,
                    self._cell_text(worksheet.cell(row_index, 4).value),
                    self._cell_text(worksheet.cell(row_index, 5).value),
                    self._cell_text(worksheet.cell(row_index, 6).value),
                    self._cell_text(worksheet.cell(row_index, 7).value),
                ]
                if actual != expected:
                    raise ValueError("worksheet values do not match")
            for cells in worksheet.iter_rows():
                for cell in cells:
                    if cell.data_type == "f":
                        formula_count += 1
        if formula_count != 0:
            raise ValueError("workbook must contain no formulas")
        return formula_count

    def build(self, report: CompanyReport, work_dir: Path) -> BuiltWorkbook:
        work_dir.mkdir(parents=True, exist_ok=True, mode=0o700)
        os.chmod(work_dir, 0o700)
        payload_path = work_dir / "workbook-payload.json"
        output_path = work_dir / report.filename
        preview_dir = work_dir / "previews"
        summary_path = work_dir / "workbook-summary.json"
        try:
            payload = report.to_workbook_payload()
            _private_json(payload_path, payload)
            preview_dir.mkdir(parents=True, exist_ok=True, mode=0o700)
            workbook = Workbook()
            for index, period in enumerate(report.periods):
                worksheet = workbook.active if index == 0 else workbook.create_sheet()
                worksheet.title = period.sheet_name
                self._write_sheet(worksheet, period)
            workbook.save(output_path)
            os.chmod(output_path, 0o600)
            formula_count = self._validate_workbook(output_path, report)
            expected_rows = [len(period.rows) for period in report.periods]
            expected_names = [period.sheet_name for period in report.periods]
            summary = {
                "status": "success",
                "schema_version": payload["schema_version"],
                "company": report.company,
                "filename": report.filename,
                "sheet_names": expected_names,
                "row_counts": expected_rows,
                "formula_count": formula_count,
                "semantic_sha256": self._semantic_sha256(payload),
                "preview_count": 0,
                "byte_size": output_path.stat().st_size,
            }
            if (
                summary.get("status") != "success"
                or summary.get("company") != report.company
                or summary.get("filename") != report.filename
                or summary.get("sheet_names") != expected_names
                or summary.get("row_counts") != expected_rows
                or summary.get("formula_count") != 0
                or not isinstance(summary.get("semantic_sha256"), str)
                or len(summary.get("semantic_sha256")) != 64
                or not output_path.is_file()
                or output_path.stat().st_size <= 0
            ):
                raise ValueError("summary mismatch")
            _private_json(summary_path, summary)
        except (OSError, ValueError, TypeError, json.JSONDecodeError):
            raise BuildError(
                ErrorCode.OUTPUT_VALIDATION_FAILED,
                "the XLSX builder result could not be validated",
            ) from None
        return BuiltWorkbook(
            path=output_path,
            sha256=sha256_file(output_path),
            byte_size=output_path.stat().st_size,
            summary=summary,
        )

class AtomicReportPublisher:
    def __init__(
        self,
        project_root: Path,
        output_root: Path,
        *,
        object_store: Optional[ManagedObjectStore] = None,
        bucket_alias: str = "arr-private",
    ) -> None:
        self._project_root = project_root.resolve()
        self._output_root = output_root.resolve()
        self._object_store = object_store
        self._bucket_alias = bucket_alias
        try:
            self._output_root.relative_to(self._project_root)
        except ValueError:
            raise ValueError("output_root must be inside project_root") from None

    @staticmethod
    def _fsync_parent(path: Path) -> None:
        descriptor = os.open(path.parent, os.O_RDONLY)
        try:
            os.fsync(descriptor)
        finally:
            os.close(descriptor)

    @classmethod
    def _atomic_copy(cls, source: Path, target: Path) -> None:
        target.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
        temporary = target.parent / f".{target.name}.tmp-{uuid.uuid4().hex}"
        try:
            shutil.copyfile(source, temporary)
            os.chmod(temporary, 0o600)
            with temporary.open("rb") as handle:
                os.fsync(handle.fileno())
            os.replace(temporary, target)
            cls._fsync_parent(target)
        finally:
            temporary.unlink(missing_ok=True)

    @classmethod
    def _atomic_json(cls, target: Path, payload: Mapping[str, Any]) -> None:
        target.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
        temporary = target.parent / f".{target.name}.tmp-{uuid.uuid4().hex}"
        try:
            _private_json(temporary, payload)
            os.replace(temporary, target)
            cls._fsync_parent(target)
        finally:
            temporary.unlink(missing_ok=True)

    @classmethod
    def _install_once(cls, source: Path, target: Path, expected_sha256: str) -> bool:
        if target.exists():
            if sha256_file(target) != expected_sha256:
                raise PublicationError(
                    ErrorCode.PUBLISH_FAILED,
                    "an immutable archive path already contains different content",
                )
            return False
        cls._atomic_copy(source, target)
        return True

    def _storage_key(self, path: Path) -> str:
        try:
            return path.resolve().relative_to(self._project_root).as_posix()
        except ValueError:
            raise PublicationError(
                ErrorCode.PUBLISH_FAILED,
                "an artifact path escaped the controlled project root",
            ) from None

    @staticmethod
    def _is_regular_file(path: Path) -> bool:
        return path.is_file() and not path.is_symlink()

    @staticmethod
    def _is_sha256(value: Any) -> bool:
        return (
            isinstance(value, str)
            and len(value) == 64
            and all(character in "0123456789abcdef" for character in value)
        )

    def _existing_publication_metadata(
        self,
        report: CompanyReport,
        reservation: ReservedReport,
        built: BuiltWorkbook,
        archive_path: Path,
        result_path: Path,
    ) -> Optional[Tuple[FileMetadata, FileMetadata]]:
        archive_present = archive_path.exists() or archive_path.is_symlink()
        result_present = result_path.exists() or result_path.is_symlink()
        if not archive_present and not result_present:
            return None
        if not self._is_regular_file(archive_path) or not self._is_regular_file(
            result_path
        ):
            raise PublicationError(
                ErrorCode.PUBLISH_FAILED,
                "an existing company report publication is incomplete",
            )

        semantic_sha256 = built.summary.get("semantic_sha256")
        if not self._is_sha256(semantic_sha256):
            raise PublicationError(
                ErrorCode.PUBLISH_FAILED,
                "the generated company report semantic identity is invalid",
            )

        try:
            result_payload = json.loads(result_path.read_text(encoding="utf-8"))
            if not isinstance(result_payload, dict):
                raise ValueError("result JSON must be an object")
            artifact_payload = result_payload.get("artifact")
            if not isinstance(artifact_payload, dict):
                raise ValueError("result JSON artifact identity is missing")
            existing_sha256 = artifact_payload.get("sha256")
            if not self._is_sha256(existing_sha256):
                raise ValueError("result JSON artifact hash is invalid")
            archive_sha256 = sha256_file(archive_path)
            if archive_sha256 != existing_sha256:
                raise ValueError("archive and result JSON hashes differ")

            storage_provider = str(artifact_payload.get("storage_provider") or "local")
            bucket_alias = str(
                artifact_payload.get("bucket_alias") or "arr-project-root"
            )
            if storage_provider in {"oss", "s3"}:
                if self._object_store is None:
                    raise ValueError("OSS artifact reader is unavailable")
                artifact_storage_key = str(artifact_payload.get("storage_key") or "")
                stored = self._object_store.inspect_committed(
                    artifact_storage_key,
                    report.filename,
                )
                if (
                    stored.role != "company_report"
                    or stored.sha256 != existing_sha256
                    or stored.byte_size != archive_path.stat().st_size
                    or stored.mime_type != XLSX_MIME
                ):
                    raise ValueError("OSS archive and local cache differ")
                artifact_byte_size = stored.byte_size
                artifact_mime_type = stored.mime_type
            elif storage_provider in {"local", "local_fixture"}:
                artifact_storage_key = self._storage_key(archive_path)
                artifact_byte_size = archive_path.stat().st_size
                artifact_mime_type = XLSX_MIME
            else:
                raise ValueError("artifact storage provider is invalid")
            expected_payload = self._success_result(
                report,
                reservation,
                artifact_storage_key,
                existing_sha256,
                semantic_sha256,
                storage_provider,
                bucket_alias,
            )
            if result_payload != expected_payload:
                raise ValueError("result JSON identity differs")

            artifact = FileMetadata(
                file_kind="company_ten_day_xlsx",
                original_filename=report.filename,
                storage_key=artifact_storage_key,
                sha256=existing_sha256,
                byte_size=artifact_byte_size,
                mime_type=artifact_mime_type,
                storage_provider=storage_provider,
                bucket_alias=bucket_alias,
            )
            result_sha256 = sha256_file(result_path)
            result_byte_size = result_path.stat().st_size
            result_storage_key = self._storage_key(result_path)
            result_mime_type = "application/json"
            if storage_provider in {"oss", "s3"}:
                uploaded_result = self._object_store.upload_committed(
                    job_id=f"company-report-{reservation.report_version_id}",
                    attempt_no=1,
                    role="result_json",
                    source=result_path,
                    original_filename=result_path.name,
                    expected_sha256=result_sha256,
                    expected_byte_size=result_byte_size,
                )
                result_storage_key = uploaded_result.object_key
                result_sha256 = uploaded_result.sha256
                result_byte_size = uploaded_result.byte_size
                result_mime_type = uploaded_result.mime_type
            result_json = FileMetadata(
                file_kind="result_json",
                original_filename=result_path.name,
                storage_key=result_storage_key,
                sha256=result_sha256,
                byte_size=result_byte_size,
                mime_type=result_mime_type,
                storage_provider=storage_provider,
                bucket_alias=bucket_alias,
            )
            artifact.validate()
            result_json.validate()
            return artifact, result_json
        except (OSError, UnicodeError, TypeError, ValueError, RepositoryError):
            raise PublicationError(
                ErrorCode.PUBLISH_FAILED,
                "an existing company report publication identity is invalid",
            ) from None

    def _archive_untracked_current(self, current_path: Path, archive_root: Path) -> None:
        if not current_path.is_file():
            return
        current_sha = sha256_file(current_path)
        legacy_path = archive_root / "legacy" / current_sha[:16] / current_path.name
        self._install_once(current_path, legacy_path, current_sha)

    @staticmethod
    def _success_result(
        report: CompanyReport,
        reservation: ReservedReport,
        artifact_storage_key: str,
        artifact_sha256: str,
        semantic_sha256: str,
        storage_provider: str,
        bucket_alias: str,
    ) -> Dict[str, Any]:
        return {
            "schema_version": RESULT_SCHEMA_VERSION,
            "status": "success",
            "company": report.company,
            "report_year": report.report_year,
            "report_month": report.report_month,
            "as_of_date": report.as_of_date.isoformat(),
            "report_version_id": reservation.report_version_id,
            "version_no": reservation.version_no,
            "artifact": {
                "filename": report.filename,
                "storage_key": artifact_storage_key,
                "sha256": artifact_sha256,
                "semantic_sha256": semantic_sha256,
                "storage_provider": storage_provider,
                "bucket_alias": bucket_alias,
            },
            "row_count": report.row_count,
            "period_row_counts": {
                period.key: len(period.rows) for period in report.periods
            },
            "daily_version_count": len(report.daily_versions),
            "booking_version_count": len(report.booking_versions),
            "warnings": [
                {
                    "code": warning.code,
                    "stage": warning.stage,
                    "period": warning.period,
                    "record_ids": list(warning.record_ids),
                }
                for warning in report.warnings
            ],
            "errors": [],
        }

    def publish(
        self,
        report: CompanyReport,
        reservation: ReservedReport,
        built: BuiltWorkbook,
        repository: ReportRepository,
        work_dir: Path,
    ) -> PublicationOutcome:
        month_root = (
            self._output_root
            / f"{report.report_year:04d}"
            / f"{report.report_month:02d}"
        )
        archive_root = month_root / "archive"
        version_root = archive_root / f"v{reservation.version_no:04d}"
        current_path = month_root / report.filename
        archive_path = version_root / report.filename
        result_path = version_root / f"{report.company}-v{reservation.version_no:04d}.result.json"
        backup_path = work_dir / "previous-current.xlsx"
        current_existed = current_path.is_file()
        archive_created = False
        result_created = False
        current_replaced = False

        try:
            month_root.mkdir(parents=True, exist_ok=True, mode=0o700)

            existing = self._existing_publication_metadata(
                report,
                reservation,
                built,
                archive_path,
                result_path,
            )
            if existing is not None:
                artifact, result_json = existing
                if not current_existed:
                    self._atomic_copy(archive_path, current_path)
                    current_replaced = True
                repository.activate_report(reservation, artifact, result_json)
                return PublicationOutcome(
                    current_path=current_path,
                    archive_path=archive_path,
                    result_path=result_path,
                    artifact=artifact,
                    result_json=result_json,
                )

            self._archive_untracked_current(current_path, archive_root)
            if current_existed:
                shutil.copyfile(current_path, backup_path)
                os.chmod(backup_path, 0o600)

            archive_created = self._install_once(
                built.path, archive_path, built.sha256
            )
            storage_provider = "local"
            bucket_alias = "arr-project-root"
            artifact_storage_key = self._storage_key(archive_path)
            if self._object_store is not None:
                uploaded_artifact = self._object_store.upload_committed(
                    job_id=f"company-report-{reservation.report_version_id}",
                    attempt_no=1,
                    role="company_report",
                    source=archive_path,
                    original_filename=report.filename,
                    expected_sha256=built.sha256,
                    expected_byte_size=built.byte_size,
                )
                storage_provider = "oss"
                bucket_alias = self._bucket_alias
                artifact_storage_key = uploaded_artifact.object_key
            result_payload = self._success_result(
                report,
                reservation,
                artifact_storage_key,
                built.sha256,
                str(built.summary.get("semantic_sha256", "")),
                storage_provider,
                bucket_alias,
            )
            if result_path.exists():
                expected = json.dumps(
                    result_payload,
                    ensure_ascii=False,
                    sort_keys=True,
                    indent=2,
                ) + "\n"
                if result_path.read_text(encoding="utf-8") != expected:
                    raise PublicationError(
                        ErrorCode.PUBLISH_FAILED,
                        "an immutable result path already contains different content",
                    )
            else:
                self._atomic_json(result_path, result_payload)
                result_created = True

            self._atomic_copy(built.path, current_path)
            current_replaced = True
            artifact = FileMetadata(
                file_kind="company_ten_day_xlsx",
                original_filename=report.filename,
                storage_key=artifact_storage_key,
                sha256=built.sha256,
                byte_size=built.byte_size,
                mime_type=XLSX_MIME,
                storage_provider=storage_provider,
                bucket_alias=bucket_alias,
            )
            result_json = FileMetadata(
                file_kind="result_json",
                original_filename=result_path.name,
                storage_key=self._storage_key(result_path),
                sha256=sha256_file(result_path),
                byte_size=result_path.stat().st_size,
                mime_type="application/json",
                storage_provider=storage_provider,
                bucket_alias=bucket_alias,
            )
            if self._object_store is not None:
                uploaded_result = self._object_store.upload_committed(
                    job_id=f"company-report-{reservation.report_version_id}",
                    attempt_no=1,
                    role="result_json",
                    source=result_path,
                    original_filename=result_path.name,
                    expected_sha256=result_json.sha256,
                    expected_byte_size=result_json.byte_size,
                )
                result_json = FileMetadata(
                    file_kind="result_json",
                    original_filename=result_path.name,
                    storage_key=uploaded_result.object_key,
                    sha256=uploaded_result.sha256,
                    byte_size=uploaded_result.byte_size,
                    mime_type=uploaded_result.mime_type,
                    storage_provider=storage_provider,
                    bucket_alias=bucket_alias,
                )
            repository.activate_report(reservation, artifact, result_json)
            return PublicationOutcome(
                current_path=current_path,
                archive_path=archive_path,
                result_path=result_path,
                artifact=artifact,
                result_json=result_json,
            )
        except Exception as error:
            if current_replaced:
                if current_existed and backup_path.is_file():
                    self._atomic_copy(backup_path, current_path)
                else:
                    current_path.unlink(missing_ok=True)
            if result_created:
                result_path.unlink(missing_ok=True)
            if archive_created:
                archive_path.unlink(missing_ok=True)
            code = getattr(error, "code", ErrorCode.PUBLISH_FAILED)
            safe_message = getattr(error, "safe_message", "company report publication failed")
            try:
                repository.mark_failed(reservation, code, safe_message)
            except Exception:
                pass
            if isinstance(error, PublicationError):
                raise
            if isinstance(error, RepositoryError):
                raise PublicationError(error.code, error.safe_message) from None
            raise PublicationError(
                ErrorCode.PUBLISH_FAILED,
                "company report publication failed",
            ) from None


def private_staging_directory(parent: Path):
    parent.mkdir(parents=True, exist_ok=True, mode=0o700)
    return tempfile.TemporaryDirectory(prefix="company-report-", dir=parent)
