<?php

namespace App\Http\Controllers\Finance;

use App\Http\Controllers\Controller;
use App\Models\ActivityLog;
use App\Models\CryptoAccount;
use App\Models\CryptoCoin;
use App\Models\FinanceGroup;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Validation\Rule;

class CryptoAccountController extends Controller
{
    public function index(Request $request)
    {
        $user = auth()->guard('finance')->user();
        $financeGroup = FinanceGroup::findOrFail((int) $user->finance_group_id);
        $this->ensureCryptoEnabled($financeGroup, $request);

        $query = CryptoAccount::with(['coin'])
            ->where('finance_group_id', $financeGroup->id);

        if ($request->filled('crypto_coin_id')) {
            $query->where('crypto_coin_id', (int) $request->crypto_coin_id);
        }

        if ($request->filled('is_active')) {
            $query->where('is_active', $request->is_active === '1');
        }

        if ($request->ajax()) {
            $accounts = $query->orderBy('created_at', 'desc')->get();

            return response()->json([
                'data' => $accounts->map(function (CryptoAccount $account) {
                    return [
                        'id' => $account->id,
                        'crypto_coin_id' => $account->crypto_coin_id,
                        'coin_name' => $account->coin ? $account->coin->name : '-',
                        'coin_icon' => $this->resolveCoinIconUrl($account->coin ? $account->coin->icon : null),
                        'address' => $account->address,
                        'is_active' => (bool) $account->is_active,
                        'created_at' => $account->created_at ? $account->created_at->format('d.m.Y H:i') : '-',
                    ];
                }),
            ]);
        }

        $coins = CryptoCoin::orderBy('name')->get(['id', 'name', 'icon']);

        return view('finance.crypto-accounts.index', compact('coins', 'financeGroup'));
    }

    public function store(Request $request)
    {
        $user = auth()->guard('finance')->user();
        $financeGroup = FinanceGroup::findOrFail((int) $user->finance_group_id);
        $this->ensureCryptoEnabled($financeGroup, $request);

        $validated = $request->validate([
            'crypto_coin_id' => ['required', 'exists:crypto_coins,id'],
            'address' => [
                'required',
                'string',
                'max:255',
                Rule::unique('crypto_accounts')->where(function ($query) use ($request) {
                    return $query->where('crypto_coin_id', (int) $request->crypto_coin_id);
                }),
            ],
            'is_active' => ['nullable', 'boolean'],
        ], [
            'crypto_coin_id.required' => 'Coin secilmelidir.',
            'crypto_coin_id.exists' => 'Gecersiz coin.',
            'address.required' => 'Adres alani zorunludur.',
            'address.unique' => 'Bu coin icin bu adres zaten kayitli.',
        ]);

        DB::beginTransaction();
        try {
            $account = CryptoAccount::create([
                'finance_group_id' => $financeGroup->id,
                'crypto_coin_id' => (int) $validated['crypto_coin_id'],
                'address' => trim((string) $validated['address']),
                'is_active' => $request->has('is_active') ? $request->boolean('is_active') : true,
                'created_by' => null,
            ]);

            ActivityLog::log(
                'finance_create_crypto_account',
                'crypto_accounts',
                "Finans kripto hesabi olusturuldu: {$account->id}",
                null,
                $account->toArray()
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Kripto hesabi basariyla eklendi.',
                'account' => $account,
            ]);
        } catch (\Exception $e) {
            DB::rollBack();

            return response()->json([
                'success' => false,
                'message' => 'Kripto hesabi eklenirken hata olustu: ' . $e->getMessage(),
            ], 500);
        }
    }

    public function show(Request $request, $id)
    {
        $user = auth()->guard('finance')->user();
        $financeGroup = FinanceGroup::findOrFail((int) $user->finance_group_id);
        $this->ensureCryptoEnabled($financeGroup, $request);

        $account = CryptoAccount::with(['coin'])
            ->where('finance_group_id', $financeGroup->id)
            ->findOrFail($id);

        return response()->json([
            'success' => true,
            'account' => $account,
        ]);
    }

    public function update(Request $request, $id)
    {
        $user = auth()->guard('finance')->user();
        $financeGroup = FinanceGroup::findOrFail((int) $user->finance_group_id);
        $this->ensureCryptoEnabled($financeGroup, $request);

        $account = CryptoAccount::where('finance_group_id', $financeGroup->id)->findOrFail($id);

        $validated = $request->validate([
            'crypto_coin_id' => ['required', 'exists:crypto_coins,id'],
            'address' => [
                'required',
                'string',
                'max:255',
                Rule::unique('crypto_accounts')
                    ->ignore($account->id)
                    ->where(function ($query) use ($request) {
                        return $query->where('crypto_coin_id', (int) $request->crypto_coin_id);
                    }),
            ],
            'is_active' => ['nullable', 'boolean'],
        ], [
            'crypto_coin_id.required' => 'Coin secilmelidir.',
            'crypto_coin_id.exists' => 'Gecersiz coin.',
            'address.required' => 'Adres alani zorunludur.',
            'address.unique' => 'Bu coin icin bu adres zaten kayitli.',
        ]);

        DB::beginTransaction();
        try {
            $oldData = $account->toArray();

            $account->update([
                'crypto_coin_id' => (int) $validated['crypto_coin_id'],
                'address' => trim((string) $validated['address']),
                'is_active' => $request->boolean('is_active'),
            ]);

            ActivityLog::log(
                'finance_update_crypto_account',
                'crypto_accounts',
                "Finans kripto hesabi guncellendi: {$account->id}",
                $oldData,
                $account->toArray()
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Kripto hesabi basariyla guncellendi.',
                'account' => $account,
            ]);
        } catch (\Exception $e) {
            DB::rollBack();

            return response()->json([
                'success' => false,
                'message' => 'Kripto hesabi guncellenirken hata olustu: ' . $e->getMessage(),
            ], 500);
        }
    }

    public function destroy(Request $request, $id)
    {
        $user = auth()->guard('finance')->user();
        $financeGroup = FinanceGroup::findOrFail((int) $user->finance_group_id);
        $this->ensureCryptoEnabled($financeGroup, $request);

        $account = CryptoAccount::where('finance_group_id', $financeGroup->id)->findOrFail($id);

        DB::beginTransaction();
        try {
            $oldData = $account->toArray();
            $account->delete();

            ActivityLog::log(
                'finance_delete_crypto_account',
                'crypto_accounts',
                "Finans kripto hesabi silindi: {$id}",
                $oldData,
                null
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Kripto hesabi basariyla silindi.',
            ]);
        } catch (\Exception $e) {
            DB::rollBack();

            return response()->json([
                'success' => false,
                'message' => 'Kripto hesabi silinirken hata olustu: ' . $e->getMessage(),
            ], 500);
        }
    }

    public function toggleStatus(Request $request, $id)
    {
        $user = auth()->guard('finance')->user();
        $financeGroup = FinanceGroup::findOrFail((int) $user->finance_group_id);
        $this->ensureCryptoEnabled($financeGroup, $request);

        $account = CryptoAccount::where('finance_group_id', $financeGroup->id)->findOrFail($id);

        DB::beginTransaction();
        try {
            $oldStatus = (bool) $account->is_active;
            $account->update(['is_active' => !$oldStatus]);

            ActivityLog::log(
                'finance_toggle_crypto_account_status',
                'crypto_accounts',
                "Finans kripto hesabi durumu degistirildi: {$account->id}",
                ['is_active' => $oldStatus],
                ['is_active' => (bool) $account->is_active]
            );

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => $account->is_active ? 'Hesap aktif edildi.' : 'Hesap pasif edildi.',
                'is_active' => (bool) $account->is_active,
            ]);
        } catch (\Exception $e) {
            DB::rollBack();

            return response()->json([
                'success' => false,
                'message' => 'Durum guncellenirken hata olustu: ' . $e->getMessage(),
            ], 500);
        }
    }

    protected function ensureCryptoEnabled(FinanceGroup $financeGroup, Request $request): void
    {
        $enabled = true;
        if (Schema::hasColumn('finance_groups', 'is_crypto_enabled')) {
            $enabled = (bool) $financeGroup->is_crypto_enabled;
        }

        if ($enabled) {
            return;
        }

        if ($request->ajax()) {
            throw new HttpResponseException(response()->json([
                'success' => false,
                'message' => 'Kripto odeme bu finans grubunda pasif.',
            ], 403));
        }

        abort(403, 'Kripto odeme bu finans grubunda pasif.');
    }

    protected function resolveCoinIconUrl(?string $icon): ?string
    {
        $icon = trim((string) $icon);
        if ($icon === '') {
            return null;
        }

        if (preg_match('/^https?:\/\//i', $icon)) {
            return $icon;
        }

        if (str_starts_with($icon, '/')) {
            return $icon;
        }

        if (!str_contains($icon, '/')) {
            return '/coins/' . ltrim($icon, '/');
        }

        return '/' . ltrim($icon, '/');
    }
}
