from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.responses import RedirectResponse, FileResponse
from pydantic import BaseModel
from typing import Optional
import subprocess
import os
import time
from PIL import Image  # Pillowライブラリを追加
import io

# レスポンスモデル
class ConvertResponse(BaseModel):
    pdf_path: str
    converted: bool
    original: Optional[str] = None
    file_size: Optional[int] = None
    error: Optional[str] = None

class HealthResponse(BaseModel):
    status: str
    service: str
    version: str
    uptime: float

# FastAPI アプリケーション
app = FastAPI(
    title="LibreOffice ドキュメント変換サービス",
    description="Word/PPT/Excel/PDF を PDF に変換し、混合内容のドキュメント処理をサポートします",
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc"
)

start_time = time.time()

@app.get("/", include_in_schema=False)
async def root():
    """ドキュメントページへリダイレクト"""
    return RedirectResponse(url="/docs")

@app.get("/health", response_model=HealthResponse)
async def health():
    """ヘルスチェックインターフェース"""
    return HealthResponse(
        status="healthy",
        service="libreoffice-converter",
        version="1.0.0",
        uptime=time.time() - start_time
    )

@app.post("/convert")
async def convert(file: UploadFile = File(...)):
    """
    ドキュメント変換インターフェース
    戻り値: PDF ファイルストリーム
    """
    try:
        # ファイル形式の検証
        allowed_extensions = [
            '.pdf', '.doc', '.docx', '.ppt', '.pptx', '.xls', '.xlsx',
            '.md', '.txt', '.rtf', '.odt', '.ods', '.odp',
            '.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff', '.webp'
        ]
        file_ext = os.path.splitext(file.filename)[1].lower()

        if file_ext not in allowed_extensions:
            raise HTTPException(
                status_code=400,
                detail=f"サポートされていないファイル形式です: {file_ext}。サポート対象: {', '.join(allowed_extensions)}"
            )

        # uploads ディレクトリの存在を確認
        upload_dir = "/app/uploads" if os.path.exists("/app/uploads") else "./uploads"
        os.makedirs(upload_dir, exist_ok=True)

        # アップロードファイルの保存
        filepath = os.path.join(upload_dir, file.filename)
        with open(filepath, "wb") as buffer:
            content = await file.read()
            buffer.write(content)

        # PDF の場合はそのまま返却
        if file_ext == '.pdf':
            return FileResponse(filepath, filename=file.filename, media_type='application/pdf')

        if file_ext == '.md':
            # Node.js スクリプトを使用して Markdown を PDF にレンダリング
            expected_pdf = filepath.rsplit('.', 1)[0] + '.pdf'
            cmd = [
                'node',
                '/app/md_to_pdf.js',
                filepath,
                expected_pdf
            ]
        elif file_ext in ['.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff', '.webp']:
            # 画像ファイルの場合は Pillow を使用して PDF に変換
            expected_pdf = filepath.rsplit('.', 1)[0] + '.pdf'

            # 画像を開いてPDFとして保存
            with Image.open(filepath) as img:
                # RGBAモードの場合はRGBに変換(透明度がある画像対応)
                if img.mode in ('RGBA', 'LA', 'P'):
                    # 白い背景に変換
                    background = Image.new('RGB', img.size, (255, 255, 255))
                    if img.mode == 'P':
                        img = img.convert('RGBA')
                    background.paste(img, mask=img.split()[-1] if img.mode in ('RGBA', 'LA') else None)
                    img = background
                elif img.mode != 'RGB':
                    img = img.convert('RGB')

                # PDFとして保存
                img.save(expected_pdf, 'PDF', resolution=100.0, save_all=False)

            # PDF生成が完了したことを確認
            if not os.path.exists(expected_pdf):
                raise HTTPException(
                    status_code=500,
                    detail="画像からPDFへの変換は成功しましたが、出力ファイルが見つかりません"
                )
            
            # 画像変換完了、PDFファイルを返却
            filename_base = os.path.splitext(file.filename)[0]
            return FileResponse(expected_pdf, filename=f"{filename_base}.pdf", media_type='application/pdf')
        else:
            # LibreOffice による変換
            cmd = [
                'soffice',
                '--headless',
                '--convert-to', 'pdf',
                '--outdir', upload_dir,
                filepath
            ]

        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            timeout=600,  # 複雑なMarkdown変換をサポートするために10分に延長
        )

        # Combine stdout and stderr for error reporting since capture_output uses PIPE
        combined_output = result.stdout if result.stdout else ""
        if result.stderr:
            combined_output += "\n" + result.stderr

        # Node.jsスクリプトの実際の出力を表示して、デバッグ
        print(f"Node.js script output: {combined_output}")

        if result.returncode != 0:
            print(f"Subprocess failed with return code: {result.returncode}")

            # Combine stdout and stderr for error reporting
            combined_output = result.stdout if result.stdout else ""
            if result.stderr:
                combined_output += "\n" + result.stderr

            print(f"Subprocess output: {combined_output}")
            raise HTTPException(
                status_code=500,
                detail=f"変換に失敗しました: {combined_output}"
            )

        # 出力ファイルの確認
        expected_pdf = filepath.rsplit('.', 1)[0] + '.pdf'
        if not os.path.exists(expected_pdf):
            raise HTTPException(
                status_code=500,
                detail="変換は成功しましたが、出力ファイルが見つかりません"
            )

        filename_base = os.path.splitext(file.filename)[0]
        return FileResponse(expected_pdf, filename=f"{filename_base}.pdf", media_type='application/pdf')

    except HTTPException:
        raise
    except subprocess.TimeoutExpired:
        raise HTTPException(status_code=504, detail="変換タイムアウト (300秒)")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/version")
async def version():
    """バージョン情報"""
    return {
        "service": "libreoffice-converter",
        "version": "1.0.0",
        "framework": "FastAPI",
        "libreoffice": "7.x"
    }
