<?php

namespace App\Services;

use App\Models\MailTemplate;
use App\Models\Batch\BatchLog;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

/**
 * SHJ メール送信処理サービス
 * 
 * メールテンプレートを使用したメール送信処理を実行するビジネスロジック
 * バッチ処理「SHJメール送信」の核となる処理を担当
 */
class ShjMailSendService
{
    /**
     * MailTemplate モデル
     *
     * @var MailTemplate
     */
    protected $mailTemplateModel;

    /**
     * BatchLog モデル
     *
     * @var BatchLog
     */
    protected $batchLogModel;

    /**
     * コンストラクタ
     *
     * @param MailTemplate $mailTemplateModel
     * @param BatchLog $batchLogModel
     */
    public function __construct(
        MailTemplate $mailTemplateModel,
        BatchLog $batchLogModel
    ) {
        $this->mailTemplateModel = $mailTemplateModel;
        $this->batchLogModel = $batchLogModel;
    }

    /**
     * SHJ メール送信処理メイン実行
     * 
     * 処理フロー:
     * 【処理1】入力パラメーターをチェックする
     * 【処理2】メール送信テンプレート情報を取得する
     * 【判断2】取得結果判定
     * 【処理3】メールを送信する
     * 【処理4】処理結果を返却する
     *
     * @param string $mailAddress メールアドレス
     * @param string $backupMailAddress 予備メールアドレス
     * @param int $mailTemplateId メールテンプレートID
     * @return array 処理結果
     */
    public function executeMailSend(string $mailAddress, string $backupMailAddress, int $mailTemplateId): array
    {
        $batchLogId = null;
        
        try {
            // バッチ処理開始ログ作成（実際のコマンド名を記録）
            $batchLog = BatchLog::createBatchLog(
                'shj-mail-send',
                BatchLog::STATUS_START,
                [
                    'mail_address' => $mailAddress,
                    'backup_mail_address' => $backupMailAddress,
                    'mail_template_id' => $mailTemplateId
                ],
                'SHJ メール送信処理開始'
            );
            $batchLogId = $batchLog->id;

            Log::info('SHJ メール送信処理開始', [
                'batch_log_id' => $batchLogId,
                'mail_address' => $mailAddress,
                'backup_mail_address' => $backupMailAddress,
                'mail_template_id' => $mailTemplateId
            ]);

            // 【処理1】入力パラメーターをチェックする
            $paramCheckResult = $this->checkInputParameters($mailAddress, $backupMailAddress, $mailTemplateId);
            if (!$paramCheckResult['valid']) {
                $this->updateBatchLog($batchLogId, 'error', $paramCheckResult['message']);
                
                return [
                    'success' => false,
                    'result_code' => 1, // 異常終了
                    'message' => $paramCheckResult['message'],
                    'batch_log_id' => $batchLogId
                ];
            }

            // 【処理2】メール送信テンプレート情報を取得する
            $templateInfo = $this->getMailTemplateInfo($mailTemplateId);

            // 【判断2】取得結果判定
            if (empty($templateInfo)) {
                $message = "メールテンプレートが存在しません。テンプレートID: {$mailTemplateId}";
                $this->updateBatchLog($batchLogId, 'error', $message);
                
                return [
                    'success' => false,
                    'result_code' => 1, // 異常終了
                    'message' => $message,
                    'batch_log_id' => $batchLogId
                ];
            }

            // 【処理3】メールを送信する
            $mailSendResult = $this->sendMail($mailAddress, $backupMailAddress, $templateInfo);

            if (!$mailSendResult['success']) {
                $this->updateBatchLog($batchLogId, 'error', $mailSendResult['message']);
                
                return [
                    'success' => false,
                    'result_code' => 1, // 異常終了
                    'message' => $mailSendResult['message'],
                    'batch_log_id' => $batchLogId
                ];
            }

            // バッチ処理完了ログ更新
            $this->updateBatchLog($batchLogId, 'success', 'SHJ メール送信処理正常完了');

            Log::info('SHJ メール送信処理完了', [
                'batch_log_id' => $batchLogId,
                'mail_send_result' => $mailSendResult
            ]);

            // 【処理4】処理結果を返却する
            return [
                'success' => true,
                'result_code' => 0, // 正常終了
                'message' => 'SHJ メール送信処理が正常に完了しました',
                'mail_send_result' => $mailSendResult,
                'batch_log_id' => $batchLogId
            ];

        } catch (\Exception $e) {
            $errorMessage = 'SHJ メール送信処理でエラーが発生: ' . $e->getMessage();
            
            if ($batchLogId) {
                $this->updateBatchLog($batchLogId, 'error', $errorMessage);
            }

            Log::error('SHJ メール送信処理エラー', [
                'batch_log_id' => $batchLogId,
                'exception' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);

            return [
                'success' => false,
                'result_code' => 1, // 異常終了
                'message' => $errorMessage,
                'details' => $e->getMessage(),
                'batch_log_id' => $batchLogId
            ];
        }
    }

    /**
     * 【処理1】入力パラメーターをチェックする
     * 
     * 仕様書に基づく詳細チェック:
     * - メールアドレス形式チェック
     * - テンプレートID存在性チェック
     *
     * @param string $mailAddress メールアドレス
     * @param string $backupMailAddress 予備メールアドレス
     * @param int $mailTemplateId メールテンプレートID
     * @return array チェック結果
     */
    private function checkInputParameters(string $mailAddress, string $backupMailAddress, int $mailTemplateId): array
    {
        try {
            // メールアドレス存在チェック（いずれか必須）
            if (empty($mailAddress) && empty($backupMailAddress)) {
                return [
                    'valid' => false,
                    'message' => 'パラメーターNG: メールアドレスまたは予備メールアドレスのいずれかは必須です'
                ];
            }

            // メールアドレス形式チェック
            if (!empty($mailAddress) && !filter_var($mailAddress, FILTER_VALIDATE_EMAIL)) {
                return [
                    'valid' => false,
                    'message' => 'パラメーターNG: メールアドレスの形式が正しくありません'
                ];
            }

            if (!empty($backupMailAddress) && !filter_var($backupMailAddress, FILTER_VALIDATE_EMAIL)) {
                return [
                    'valid' => false,
                    'message' => 'パラメーターNG: 予備メールアドレスの形式が正しくありません'
                ];
            }

            // メールテンプレートID形式チェック
            if ($mailTemplateId <= 0) {
                return [
                    'valid' => false,
                    'message' => 'パラメーターNG: メールテンプレートIDは正の整数である必要があります'
                ];
            }

            Log::info('入力パラメーターチェック完了', [
                'mail_address' => $mailAddress,
                'backup_mail_address' => $backupMailAddress,
                'mail_template_id' => $mailTemplateId
            ]);

            return [
                'valid' => true,
                'message' => 'パラメーターチェックOK'
            ];

        } catch (\Exception $e) {
            Log::error('入力パラメーターチェックエラー', [
                'error' => $e->getMessage()
            ]);

            return [
                'valid' => false,
                'message' => 'パラメーターチェック中にエラーが発生しました: ' . $e->getMessage()
            ];
        }
    }

    /**
     * 【処理2】メール送信テンプレート情報を取得する
     * 
     * 仕様書に基づくSQLクエリ:
     * SELECT エリアマネージャー同報, bccアドレス, 件名, 本文
     * FROM メール送信テンプレート
     * WHERE 使用プログラムID = 入力パラメーター使用プログラムID
     * AND 使用フラグ = 1
     *
     * @param int $mailTemplateId メールテンプレートID（使用プログラムIDとして扱う）
     * @return MailTemplate|null メールテンプレート情報
     */
    private function getMailTemplateInfo(int $mailTemplateId): ?MailTemplate
    {
        try {
            // 仕様書に記載されたSQLクエリに基づくメールテンプレート情報取得
            // 注意: 仕様書では「使用プログラムID」を条件にしているが、
            // 入力パラメーターは「メールテンプレートID」なので、pg_idで検索
            $templateInfo = $this->mailTemplateModel::where('pg_id', $mailTemplateId)
                ->where('use_flag', 1)
                ->first();

            if ($templateInfo) {
                Log::info('メールテンプレート情報取得完了', [
                    'mail_template_id' => $mailTemplateId,
                    'template_found' => true,
                    'subject' => $templateInfo->getSubject()
                ]);
            } else {
                Log::warning('メールテンプレート情報取得結果', [
                    'mail_template_id' => $mailTemplateId,
                    'template_found' => false,
                    'message' => 'テンプレートが見つかりません'
                ]);
            }

            return $templateInfo;

        } catch (\Exception $e) {
            Log::error('メールテンプレート情報取得エラー', [
                'mail_template_id' => $mailTemplateId,
                'error' => $e->getMessage()
            ]);

            throw $e;
        }
    }

    /**
     * 【処理3】メールを送信する
     * 
     * 仕様書に基づくmb_send_mail関数使用:
     * - 送信者: 処理2で取得したメールアドレス（処理1で予備メールアドレス）
     * - タイトル: 処理2で取得したタイトル
     * - 本文: 処理2で取得した本文（※現在の文字列は「So-Manager一般的なWebサイト内部処理」参照）
     * - 追加ヘッダ: 処理2で取得したbccアドレス（※値が設定されている場合のみ）
     *
     * @param string $mailAddress メールアドレス
     * @param string $backupMailAddress 予備メールアドレス
     * @param MailTemplate $templateInfo テンプレート情報
     * @return array 送信結果
     */
    private function sendMail(string $mailAddress, string $backupMailAddress, MailTemplate $templateInfo): array
    {
        try {
            // 送信先アドレス決定（優先: メールアドレス、代替: 予備メールアドレス）
            $toAddress = !empty($mailAddress) ? $mailAddress : $backupMailAddress;
            
            // メール内容取得
            $subject = $templateInfo->getSubject() ?? '';
            $message = $templateInfo->getText() ?? '';
            
            // 追加ヘッダ設定
            $headers = $this->buildMailHeaders($templateInfo);
            
            Log::info('メール送信準備完了', [
                'to_address' => $toAddress,
                'subject' => $subject,
                'has_bcc' => !empty($templateInfo->getBccAddress()),
                'manager_cc_enabled' => $templateInfo->isManagerCcEnabled()
            ]);

            // mb_send_mail関数を使用してメール送信
            $sendResult = mb_send_mail(
                $toAddress,     // 送信先
                $subject,       // 件名
                $message,       // 本文
                $headers        // 追加ヘッダ
            );

            if ($sendResult) {
                Log::info('メール送信成功', [
                    'to_address' => $toAddress,
                    'subject' => $subject
                ]);

                return [
                    'success' => true,
                    'message' => 'メール送信が正常に完了しました',
                    'to_address' => $toAddress,
                    'subject' => $subject
                ];
            } else {
                $errorMessage = 'mb_send_mail関数でメール送信に失敗しました';
                Log::error('メール送信失敗', [
                    'to_address' => $toAddress,
                    'subject' => $subject,
                    'error' => $errorMessage
                ]);

                return [
                    'success' => false,
                    'message' => $errorMessage
                ];
            }

        } catch (\Exception $e) {
            $errorMessage = 'メール送信中にエラーが発生: ' . $e->getMessage();
            Log::error('メール送信エラー', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);

            return [
                'success' => false,
                'message' => $errorMessage
            ];
        }
    }

    /**
     * メールヘッダを構築
     * 
     * 仕様書に基づく設定:
     * - BCCアドレス: 値が設定されている場合のみ追加
     * - エリアマネージャー同報: フラグが有効な場合の処理
     *
     * @param MailTemplate $templateInfo テンプレート情報
     * @return string メールヘッダ
     */
    private function buildMailHeaders(MailTemplate $templateInfo): string
    {
        $headers = [];

        // BCCアドレス設定（値が設定されている場合のみ）
        $bccAddress = $templateInfo->getBccAddress();
        if (!empty($bccAddress)) {
            $headers[] = "Bcc: {$bccAddress}";
        }

        // エリアマネージャー同報フラグが有効な場合
        // ※具体的な処理内容は仕様書に詳細がないため、ログ出力のみ
        if ($templateInfo->isManagerCcEnabled()) {
            Log::info('エリアマネージャー同報フラグが有効です', [
                'mail_template_id' => $templateInfo->mail_template_id
            ]);
            // 実際のエリアマネージャーアドレス取得・設定処理は追加仕様が必要
        }

        // From設定（システム設定から取得）
        $fromAddress = config('mail.from.address', 'noreply@so-manager.com');
        $headers[] = "From: {$fromAddress}";

        // Content-Type設定（日本語対応）
        $headers[] = "Content-Type: text/plain; charset=UTF-8";

        return implode("\r\n", $headers);
    }

    /**
     * バッチログ作成
     *
     * @param string $processName プロセス名
     * @param string $status ステータス
     * @param array $params パラメータ
     * @return int バッチログID
     */
    private function createBatchLog(string $processName, string $status, array $params = []): int
    {
        return $this->batchLogModel->create([
            'process_name' => $processName,
            'status' => $status,
            'start_time' => now(),
            'parameters' => json_encode($params),
            'message' => 'バッチ処理開始'
        ])->id;
    }

    /**
     * バッチログ更新
     *
     * @param int $batchLogId バッチログID
     * @param string $status ステータス
     * @param string $message メッセージ
     * @return void
     */
    private function updateBatchLog(int $batchLogId, string $status, string $message): void
    {
        $this->batchLogModel->where('id', $batchLogId)->update([
            'status' => $status,
            'end_time' => now(),
            'message' => $message
        ]);
    }
}