<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreTradeRequest;
use App\Http\Requests\UpdateTradeRequest;
use App\Models\EmotionTag;
use App\Models\MistakeTag;
use App\Models\Trade;
use App\Services\FeatureAccessService;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;

class TradeController extends Controller
{
    public function index(): View
    {
        $trades = Trade::query()
            ->where('user_id', Auth::id())
            ->latest('opened_at')
            ->latest()
            ->paginate(10);

        return view('trades.index', compact('trades'));
    }

    public function create(): View
    {
        MistakeTag::ensureDefaults();
        EmotionTag::seedDefaults();

        return view('trades.create', [
            'mistakeTags' => $this->availableMistakeTags(),
            'emotionTags' => EmotionTag::activeOrdered(),
        ]);
    }

    public function exportPdf()
    {
        $trades = Trade::query()
            ->where('user_id', Auth::id())
            ->latest('opened_at')
            ->latest()
            ->get();

        $totals = [
            'total_trades' => $trades->count(),
            'wins' => $trades->where('profit_loss', '>', 0)->count(),
            'losses' => $trades->where('profit_loss', '<', 0)->count(),
            'profit_loss' => (float) $trades->sum('profit_loss'),
        ];

        $pdf = Pdf::loadView('trades.pdf.index', [
            'trades' => $trades,
            'totals' => $totals,
            'generatedAt' => now(),
            'user' => Auth::user(),
        ])->setPaper('a4', 'landscape');

        return $pdf->download('vizutrade-trades-'.now()->format('Y-m-d').'.pdf');
    }

    public function calendar(Request $request): View
    {
        try {
            $currentMonth = Carbon::createFromFormat('Y-m', $request->query('month', now()->format('Y-m')))->startOfMonth();
        } catch (\Throwable) {
            $currentMonth = now()->startOfMonth();
        }

        $monthStart = $currentMonth->copy()->startOfMonth();
        $monthEnd = $currentMonth->copy()->endOfMonth();

        $trades = Trade::query()
            ->where('user_id', Auth::id())
            ->where(function ($query) use ($monthStart, $monthEnd): void {
                $query
                    ->whereBetween('opened_at', [$monthStart, $monthEnd])
                    ->orWhere(function ($query) use ($monthStart, $monthEnd): void {
                        $query
                            ->whereNull('opened_at')
                            ->whereBetween('created_at', [$monthStart, $monthEnd]);
                    });
            })
            ->orderBy('opened_at')
            ->orderBy('created_at')
            ->get();

        $calendarDays = collect(range(1, $currentMonth->daysInMonth))->map(function (int $day) use ($currentMonth, $trades): array {
            $date = $currentMonth->copy()->day($day);

            return [
                'date' => $date,
                'trades' => $trades->filter(function (Trade $trade) use ($date): bool {
                    $tradeDate = $trade->opened_at ?? $trade->created_at;

                    return $tradeDate?->isSameDay($date) ?? false;
                }),
            ];
        });

        return view('trades.calendar', [
            'calendarDays' => $calendarDays,
            'currentMonth' => $currentMonth,
            'previousMonth' => $currentMonth->copy()->subMonth()->format('Y-m'),
            'nextMonth' => $currentMonth->copy()->addMonth()->format('Y-m'),
        ]);
    }

    public function store(StoreTradeRequest $request): RedirectResponse
    {
        $features = app(FeatureAccessService::class);
        $user = $request->user();

        if ($features->tradeLimitReached($user)) {
            return redirect()
                ->route('subscriptions.index')
                ->with('error', 'Your current subscription plan has reached its trade limit.');
        }

        if ($request->hasFile('screenshot') && ! $features->allowed($user, 'screenshot_uploads')) {
            return redirect()
                ->route('subscriptions.index')
                ->with('error', 'Your current subscription plan does not include screenshot uploads.');
        }

        $data = $request->validated();
        $data['user_id'] = Auth::id();
        $data['symbol'] = strtoupper($data['symbol']);
        $data['followed_risk_reward'] = $request->boolean('followed_risk_reward');
        $data['avoided_overtrading'] = $request->boolean('avoided_overtrading');
        $mistakeTags = $data['mistake_tags'] ?? [];

        if ($request->hasFile('screenshot')) {
            $data['screenshot_path'] = $request->file('screenshot')->store('trade-screenshots', 'public');
        }

        unset($data['screenshot'], $data['mistake_tags']);

        $trade = Trade::create($data);
        $trade->mistakeTags()->syncWithPivotValues($mistakeTags, ['user_id' => Auth::id()]);

        return redirect()
            ->route('trades.show', $trade)
            ->with('success', 'Trade created successfully.');
    }

    public function show(Trade $trade): View
    {
        $this->authorizeOwner($trade);

        $trade->load('mistakeTags', 'comments.mentor');

        return view('trades.show', compact('trade'));
    }

    public function edit(Trade $trade): View
    {
        $this->authorizeOwner($trade);
        MistakeTag::ensureDefaults();
        EmotionTag::seedDefaults();
        $trade->load('mistakeTags');

        return view('trades.edit', [
            'trade' => $trade,
            'mistakeTags' => $this->availableMistakeTags(),
            'emotionTags' => EmotionTag::activeOrdered(),
        ]);
    }

    public function update(UpdateTradeRequest $request, Trade $trade): RedirectResponse
    {
        $this->authorizeOwner($trade);

        if ($request->hasFile('screenshot') && ! app(FeatureAccessService::class)->allowed($request->user(), 'screenshot_uploads')) {
            return redirect()
                ->route('subscriptions.index')
                ->with('error', 'Your current subscription plan does not include screenshot uploads.');
        }

        $data = $request->validated();
        $data['symbol'] = strtoupper($data['symbol']);
        $data['followed_risk_reward'] = $request->boolean('followed_risk_reward');
        $data['avoided_overtrading'] = $request->boolean('avoided_overtrading');
        $mistakeTags = $data['mistake_tags'] ?? [];

        if ($request->boolean('remove_screenshot') && $trade->screenshot_path) {
            Storage::disk('public')->delete($trade->screenshot_path);
            $data['screenshot_path'] = null;
        }

        if ($request->hasFile('screenshot')) {
            if ($trade->screenshot_path) {
                Storage::disk('public')->delete($trade->screenshot_path);
            }

            $data['screenshot_path'] = $request->file('screenshot')->store('trade-screenshots', 'public');
        }

        unset($data['screenshot'], $data['remove_screenshot'], $data['mistake_tags']);

        $trade->update($data);
        $trade->mistakeTags()->syncWithPivotValues($mistakeTags, ['user_id' => Auth::id()]);

        return redirect()
            ->route('trades.show', $trade)
            ->with('success', 'Trade updated successfully.');
    }

    public function destroy(Trade $trade): RedirectResponse
    {
        $this->authorizeOwner($trade);

        if ($trade->screenshot_path) {
            Storage::disk('public')->delete($trade->screenshot_path);
        }

        $trade->delete();

        return redirect()
            ->route('trades.index')
            ->with('success', 'Trade deleted successfully.');
    }

    private function authorizeOwner(Trade $trade): void
    {
        abort_unless($trade->user_id === Auth::id(), 403);
    }

    private function availableMistakeTags()
    {
        return MistakeTag::query()
            ->where('is_active', true)
            ->where(function ($query): void {
                $query->whereNull('user_id')->orWhere('user_id', Auth::id());
            })
            ->orderBy('name')
            ->get();
    }
}
