<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Http\Traits\AuthenticatesUser;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Mpdf\Mpdf;
use Illuminate\Contracts\View\View;
use function base_path;

class ReceiptController extends Controller
{
    use AuthenticatesUser;

    /**
     * 領収書宛名入力画面を表示する。
     * 契約IDに基づき、領収書宛名入力フォームを表示する。
     * 
     * @param string $management_code 運営元コード
     * @param string $contract_id 契約ID
     * @return mixed ビュー応答またはリダイレクト
     */
    public function input(string $management_code, string $contract_id): mixed
    {
        if ($redirect = $this->handleSessionExpired('領収書宛名入力', false)) {
            return $redirect;
        }

        // ヘッダー表示のためユーザー名取得
        $user_id = session('user_id');
        $user_name = DB::table('user')->where('user_id', $user_id)->value('user_name');

        $management = session('management');
        $management_id = $management->management_id;

        // セキュリティのため、そのユーザーの契約のみアクセス可能
        $contract = DB::table('regular_contract')
            ->join('park', 'regular_contract.park_id', '=', 'park.park_id')
            ->where('contract_id', $contract_id)
            ->where('user_id', $user_id)
            ->where('park.management_id', $management_id)
            ->first();

        if (!$contract) {
            // アクセス権限がない場合、エラーログで記録
            \Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " アクセス権限なし: user_id=" . $user_id . ", contract_id=" . $contract_id);
            abort(403, 'アクセス権限がありません。');
        }

        // システム操作の追跡のため、アクセスを記録
        \Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 領収書宛名入力画面にアクセス: user_id=" . $user_id . ", contract_id=" . $contract_id);

        return view('receipt.input', [
            'user_name' => $user_name,
            'contract_id' => $contract_id,
            'management_code' => $management_code,
        ]);
    }

    /**
     * 領収書の宛名入力内容を確認し、保存する。
     * 
     * @param Request $request リクエストオブジェクト
     * @param string $management_code 運営元コード
     * @param string $contract_id 契約ID
     * @return mixed PDFダウンロードまたはリダイレクト
     */
    public function issue(Request $request, string $management_code, string $contract_id): mixed
    {
        if ($redirect = $this->handleSessionExpired('領収書宛名入力', false)) {
            return $redirect;
        }

        $user_id = session('user_id');

        // 既存レコードがある場合、再発行を促す
        $exists = DB::table('inv_publish')->where('contract_id', $contract_id)->exists();
        if ($exists) {
            // エラー時はinput画面に戻し、メッセージ表示
            \Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 領収書発行済み: user_id=" . $user_id . ", contract_id=" . $contract_id);
            return redirect()->back()->withInput()->withErrors(['contract_id' => __('messages.RECEIPT_E000001')]);
        }

        $receipt_name = trim($request->input('receipt_name') ?? '');
        $keisho = $request->input('keisho');

        // 宛名必須チェック
        if (empty($receipt_name)) {
            return redirect()->back()->withInput()->withErrors(['contract_id' => str_replace('{0}', '宛名', __('messages.SYSCOMMON_E000001'))]);
        }

        // 4バイト文字（絵文字等）を防ぐ
        if (preg_match('/[\xF0-\xF7][\x80-\xBF]{3}/', $receipt_name)) {
            return redirect()->back()->withInput()->withErrors(['contract_id' => str_replace('{0}', '宛名', __('messages.SYSCOMMON_E000046'))]);
        }

        // 文字数チェック
        if (mb_strlen($receipt_name) > 30) {
            return redirect()->back()->withInput()->withErrors(['contract_id' => str_replace(['{0}', '{1}'], ['宛名', '30'], __('messages.SYSCOMMON_E000011'))]);
        }

        // 敬称選択チェック
        if (empty($keisho)) {
            return redirect()->back()->withInput()->withErrors(['contract_id' => str_replace('{0}', '敬称', __('messages.SYSCOMMON_E000047'))]);
        }

        // 領収書再発行を可能にするため、領収書発行履歴登録
        $inv_name = $receipt_name . $keisho;
        $now = date('Y-m-d H:i:s');
        $seq = DB::table('inv_publish')->max('seq') ?? 0;
        $seq = $seq + 1;
        DB::table('inv_publish')->insert([
            'seq' => $seq,
            'user_id' => $user_id,
            'contract_id' => $contract_id,
            'inv_name' => $inv_name,
            'published_at' => date('Y-m-d'),
            'type' => 0,
            'count' => 0,
            'created_at' => $now,
            'updated_at' => null,
        ]);

        // 領収書発行履歴の登録成功を記録
        \Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 領収書発行履歴登録成功: user_id=" . $user_id . ", contract_id=" . $contract_id . ", seq=" . $seq);

        $management = session('management');

        // 完了後はdownloadメソッドを直接呼び出し（初回発行のため再発行フラグはfalseで渡す）
        $is_reissue = false;
        return $this->download($management->management_code, $contract_id, $is_reissue);
    }

    /**
     * 領収書PDFをダウンロードする。
     * 契約IDに基づきデータを取得し、PDFを生成してレスポンスとして返す。
     * 
     * @param string $management_code 運営元コード
     * @param string $contract_id 契約ID
     * @param bool $is_reissue 再発行フラグ（デフォルトtrue）
     * @return mixed PDFダウンロードまたはリダイレクト
     * @throws \Symfony\Component\HttpKernel\Exception\HttpException アクセス権限エラーまたはシステムエラー時
     */
    public function download(string $management_code, string $contract_id, bool $is_reissue = true): mixed
    {
        try {
            if ($redirect = $this->handleSessionExpired('領収書ダウンロード', false)) {
                return $redirect;
            }

            $user_id = session('user_id');
            $management = session('management');
            $management_id = $management->management_id;

            $contract_id = (int) $contract_id;

            // PDFに表示する契約情報を取得
            $contract = DB::table('regular_contract')
                ->join('park', 'regular_contract.park_id', '=', 'park.park_id')
                ->where('contract_id', $contract_id)
                ->where('user_id', $user_id)
                ->where('park.management_id', $management_id)
                ->select('regular_contract.*', 'park.park_name')
                ->first();

            // PDFに表示する領収書名前を取得
            $inv = DB::table('inv_publish')
                ->where('contract_id', $contract_id)
                ->where('user_id', $user_id)
                ->first();

            // PDFに表示する事業者情報を取得
            $inv_setting = DB::table('inv_setting')
                ->where('management_id', $management_id)
                ->first();

            // 社員側の社判画像を参照するため、シンボリックリンクを作成 (company_image_path が存在する場合のみ)
            if (!empty($inv_setting->company_image_path)) {
                $krgmStoragePath = config('app.krgm_storage_path');
                $linkPath = public_path('other-storage');
                if (!file_exists($krgmStoragePath)) {
                    \Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 社判画像保存フォルダ発見不可: " . $krgmStoragePath . ", user_id=" . $user_id . ", contract_id=" . $contract_id);
                    throw new \Exception();
                }
                if (!file_exists($linkPath)) {
                    $result = symlink($krgmStoragePath, $linkPath);
                    \Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 社判画像参照リンク作成。結果: " . ($result ? '成功' : '失敗') . ", user_id=" . $user_id . ", contract_id=" . $contract_id);
                    if (!$result) {
                        \Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 社判画像参照リンク作成失敗。user_id=" . $user_id . ", contract_id=" . $contract_id);
                        throw new \Exception();
                    }
                }
            }

            // ダウンロード回数をカウントアップ
            DB::table('inv_publish')
                ->where('contract_id', $contract_id)
                ->where('user_id', $user_id)
                ->update([
                    'count' => DB::raw('count + 1'),
                    'updated_at' => now(),
                ]);

            // BladeテンプレートをHTMLにレンダリング
            $html = view('receipt.pdf', [
                'contract' => $contract,
                'inv' => $inv,
                'inv_setting' => $inv_setting,
                'is_reissue' => $is_reissue,
            ])->render();

            // mPDF最新版（autoload対応）
            $mpdf = new \Mpdf\Mpdf([
                'mode' => 'ja',
                'format' => 'A4',
                'custom_font_dir' => resource_path('fonts'),
                'custom_font_data' => [
                    'noto_sans_jp' => [
                        'R' => 'NotoSansJP-Regular.ttf',   // 通常フォント
                        'B' => 'NotoSansJP-Bold.ttf',      // 太字フォント
                    ]
                ],
                'default_font' => 'noto_sans_jp',
            ]);

            $mpdf->WriteHTML($html);

            // システム操作の追跡のため、アクセスを記録
            if ($is_reissue) {
                \Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 領収書再発行ダウンロード実行: user_id=" . $user_id . ", contract_id=" . $contract_id);
            } else {
                \Log::info("[INFO] " . now()->format('Y-m-d H:i:s') . " 領収書新規発行ダウンロード実行: user_id=" . $user_id . ", contract_id=" . $contract_id);
            }

            // PDFダウンロード
            return response($mpdf->Output('receipt_' . $contract_id . '.pdf', 'S'))
                ->header('Content-Type', 'application/pdf')
                ->header('Content-Disposition', 'attachment; filename="receipt_' . $contract_id . '.pdf"');
        } catch (\Exception $e) {
            // PDF生成エラーを記録
            \Log::error("[ERROR] " . now()->format('Y-m-d H:i:s') . " 領収書PDFダウンロードエラー: user_id=" . $user_id . ", contract_id=" . $contract_id . ", error=" . $e->getMessage());
            abort(500, '領収書ダウンロードに失敗しました。');
        }
    }
}
