<?php

namespace App\Console\Commands;

use App\Services\StorageChargeService;
use App\StorageContract;
use App\Traits\SendsTemplateEmail;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;

class RenewStorageContractsCommand extends Command
{
    use SendsTemplateEmail;

    protected $signature = 'storage:renew
                            {--date= : 更新対象日 (Y-m-d, default: today)}
                            {--dry-run : 実行せずに対象を表示}
                            {--id= : 特定の契約IDのみ処理 (テスト用)}';

    protected $description = '保管料の自動更新課金を実行する';

    public function handle()
    {
        $date = $this->option('date') ?: now()->toDateString();
        $dryRun = $this->option('dry-run');
        $specificId = $this->option('id');

        $this->info("保管料自動更新: 対象日={$date}" . ($dryRun ? ' [DRY-RUN]' : ''));

        // 更新対象の契約を取得
        $query = StorageContract::dueForRenewal($date)->with(['user', 'product']);

        if ($specificId) {
            $query->where('id', $specificId);
        }

        $contracts = $query->get();

        if ($contracts->isEmpty()) {
            $this->info('更新対象の契約はありません。');
            return 0;
        }

        $this->info("更新対象: {$contracts->count()}件");

        $service = new StorageChargeService();
        $successCount = 0;
        $failCount = 0;

        // ユーザーごとに更新成功した契約を収集（メール統合用）
        $renewedByUser = [];

        foreach ($contracts as $contract) {
            $userName = $contract->user->full_name ?? $contract->user->name ?? 'ID:' . $contract->user_id;
            $productName = $contract->product->name ?? 'ID:' . $contract->product_id;

            if ($dryRun) {
                $this->line("  [DRY-RUN] 契約ID:{$contract->id} ユーザー:{$userName} 商品:{$productName} 金額:¥{$contract->amount}");
                continue;
            }

            try {
                // renewContract は「契約作成から 30 日未満のガード」に当たった場合 false を返す。
                // この場合は更新が行われていないため、成功カウントやメール送信対象には入れない。
                $renewed = $service->renewContract($contract);
                if (!$renewed) {
                    $this->line("  [SKIP] 契約ID:{$contract->id} ユーザー:{$userName} (作成 30 日未満のためスキップ)");
                    continue;
                }
                $successCount++;
                $this->line("  [OK] 契約ID:{$contract->id} ユーザー:{$userName}");

                // ユーザーごとに成功した契約を収集
                $userId = $contract->user_id;
                if (!isset($renewedByUser[$userId])) {
                    $renewedByUser[$userId] = [];
                }
                $renewedByUser[$userId][] = $contract;
            } catch (\Exception $e) {
                $failCount++;
                $this->error("  [NG] 契約ID:{$contract->id} ユーザー:{$userName} エラー:{$e->getMessage()}");
                Log::error("storage:renew 更新失敗 contract_id={$contract->id}, error={$e->getMessage()}");
            }
        }

        // ユーザーごとにまとめてメール送信
        if (!$dryRun) {
            foreach ($renewedByUser as $userId => $userContracts) {
                $this->sendRenewalEmail($userContracts);
            }

            $this->info("完了: 成功={$successCount}件, 失敗={$failCount}件, メール送信={$this->countUsers($renewedByUser)}通");
        }

        return $failCount > 0 ? 1 : 0;
    }

    /**
     * ユーザーに更新完了メールを送信（複数契約を1通にまとめる）
     *
     * @param StorageContract[] $contracts 同一ユーザーの更新成功した契約一覧
     */
    protected function sendRenewalEmail(array $contracts)
    {
        try {
            $firstContract = $contracts[0];
            $user = $firstContract->user;

            if (count($contracts) === 1) {
                // 1件の場合：通常のメール
                $this->sendTemplateEmail('email_storage_renewal_complete', $user->email, [
                    'user_name' => $user->full_name ?? $user->name,
                    'product_name' => $firstContract->product->name ?? '',
                    'amount' => number_format($firstContract->amount),
                    'next_renewal_date' => $firstContract->next_renewal_date->format('Y年m月d日'),
                ]);
            } else {
                // 複数件の場合：まとめたメール
                $productLines = [];
                $totalAmount = 0;
                foreach ($contracts as $contract) {
                    $productName = $contract->product->name ?? '商品ID:' . $contract->product_id;
                    $productLines[] = "・{$productName}（¥" . number_format($contract->amount) . "）";
                    $totalAmount += $contract->amount;
                }

                $this->sendTemplateEmail('email_storage_renewal_complete', $user->email, [
                    'user_name' => $user->full_name ?? $user->name,
                    'product_name' => implode("\n", $productLines),
                    'amount' => number_format($totalAmount) . "（" . count($contracts) . "セット分）",
                    'next_renewal_date' => $firstContract->next_renewal_date->format('Y年m月d日'),
                ]);
            }
        } catch (\Exception $e) {
            $contractIds = implode(',', array_map(fn($c) => $c->id, $contracts));
            Log::warning("storage:renew メール送信失敗 contract_ids={$contractIds}, error={$e->getMessage()}");
        }
    }

    private function countUsers(array $renewedByUser): int
    {
        return count($renewedByUser);
    }
}
