#!/usr/bin/env python3
"""
Upload an invoicing Excel workbook via the public presigned flow.

Example:
    python3 upload_excel_source.py "/path/to/file.xlsx" TOKEN \
        --base-url https://api2.fincome.co/product/v1 \
        --name "My Invoicing Upload" \
        --freshness-date 2024-07-01
"""

import argparse
import datetime as dt
import mimetypes
import os
import sys
from typing import Any, Dict

import requests

DEFAULT_BASE_URL = "http://localhost:8000"


class UploadError(RuntimeError):
    pass


def initiate_upload(base_url: str, token: str) -> Dict[str, Any]:
    url = f"{base_url.rstrip('/')}/v1/import/sources/invoicing/excel/initiate_upload"
    response = requests.post(url, headers={"Authorization": f"Bearer {token}"}, timeout=30)
    if response.status_code != 201:
        raise UploadError(
            f"Initiate upload failed ({response.status_code}): {response.text.strip()}"
        )
    return response.json()


def upload_to_s3(upload_info: Dict[str, Any], file_path: str) -> None:
    url = upload_info["url"]
    fields = upload_info["fields"]
    mime_type, _ = mimetypes.guess_type(file_path)
    if mime_type is None:
        mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    with open(file_path, "rb") as file_obj:
        files = {"file": (os.path.basename(file_path), file_obj, mime_type)}
        response = requests.post(url, data=fields, files=files, timeout=120)
    if response.status_code not in (200, 204):
        raise UploadError(
            f"S3 upload failed ({response.status_code}): {response.text.strip()}"
        )


def confirm_upload(
    base_url: str,
    token: str,
    upload_id: int,
    name: str,
    freshness_date: str,
) -> Dict[str, Any]:
    url = f"{base_url.rstrip('/')}/v1/import/sources/invoicing/excel/confirm_upload"
    payload: Dict[str, Any] = {"upload_id": upload_id, "name": name}
    if freshness_date:
        payload["freshness_date"] = freshness_date

    response = requests.post(
        url,
        headers={
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json",
        },
        json=payload,
        timeout=60,
    )
    if response.status_code != 201:
        raise UploadError(
            f"Confirm upload failed ({response.status_code}): {response.text.strip()}"
        )
    return response.json()


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Create an invoicing CSV source using the presigned Excel upload flow.",
    )
    parser.add_argument("excel_path", help="Path to the Excel (.xlsx) file to upload.")
    parser.add_argument("token", help="Bearer token for the API.")
    parser.add_argument(
        "--base-url",
        default=DEFAULT_BASE_URL,
        help=f"Base URL of the Product API (default: {DEFAULT_BASE_URL}).",
    )
    parser.add_argument(
        "--name",
        help="Name of the new source (default: derived from file name).",
    )
    parser.add_argument(
        "--freshness-date",
        help="Freshness date in YYYY-MM-DD (default: today's date).",
    )
    return parser.parse_args()


def main() -> None:
    args = parse_args()
    excel_path = os.path.abspath(args.excel_path)
    if not os.path.isfile(excel_path):
        raise SystemExit(f"Excel file not found: {excel_path}")

    name = args.name or os.path.splitext(os.path.basename(excel_path))[0]
    freshness_date = args.freshness_date or dt.date.today().isoformat()

    print("Initiating upload …")
    upload_response = initiate_upload(args.base_url, args.token)
    upload_id = upload_response["upload_id"]
    print(f"Received upload_id={upload_id}")

    print("Uploading file to S3 …")
    upload_to_s3(upload_response["upload"], excel_path)
    print("Upload complete.")

    print("Confirming upload …")
    source = confirm_upload(args.base_url, args.token, upload_id, name, freshness_date)
    print("Source created successfully:")
    print(source)


if __name__ == "__main__":
    try:
        main()
    except UploadError as exc:
        print(f"Error: {exc}", file=sys.stderr)
        sys.exit(1)
