<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Category;
use App\Models\CategoryKeyword;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;

class CategoryController extends Controller
{
    /**
     * Listar todas as categorias do usuário (hierárquico)
     */
    public function index(Request $request): JsonResponse
    {
        $query = Category::where('user_id', Auth::id())
            ->with(['keywords', 'children.keywords']);

        if ($request->has('type')) {
            $query->ofType($request->type);
        }

        if ($request->has('is_active')) {
            $query->where('is_active', $request->boolean('is_active'));
        }

        // Se flat=true, retorna todas as categorias
        if ($request->boolean('flat')) {
            $categories = $query->orderBy('name')->get();
        } else {
            // Retorna apenas categorias raiz com filhas aninhadas
            $categories = $query->root()->orderBy('order')->orderBy('name')->get();
        }

        return response()->json([
            'success' => true,
            'data' => $categories,
            'types' => Category::TYPES,
        ]);
    }

    /**
     * Criar nova categoria
     */
    public function store(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'name' => 'required|string|max:100',
            'parent_id' => 'nullable|exists:categories,id',
            'type' => ['nullable', Rule::in(array_keys(Category::TYPES))],
            'description' => 'nullable|string',
            'color' => 'nullable|string|max:7',
            'icon' => 'nullable|string|max:50',
            'order' => 'nullable|integer',
            'is_active' => 'nullable|boolean',
            'keywords' => 'nullable|array',
            'keywords.*' => 'string|max:100',
        ]);

        // Verificar se parent_id pertence ao usuário
        if (!empty($validated['parent_id'])) {
            $parent = Category::where('user_id', Auth::id())
                ->findOrFail($validated['parent_id']);
            // Herdar tipo do pai se não especificado
            if (empty($validated['type'])) {
                $validated['type'] = $parent->type;
            }
        }

        $keywords = $validated['keywords'] ?? [];
        unset($validated['keywords']);

        $validated['user_id'] = Auth::id();
        $validated['type'] = $validated['type'] ?? Category::TYPE_EXPENSE;

        DB::beginTransaction();
        try {
            $category = Category::create($validated);

            // Adicionar palavras-chave
            foreach ($keywords as $keyword) {
                $category->keywords()->create([
                    'keyword' => trim($keyword),
                    'is_case_sensitive' => false,
                    'is_active' => true,
                ]);
            }

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Categoria criada com sucesso',
                'data' => $category->load(['keywords', 'parent', 'children']),
            ], 201);

        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Erro ao criar categoria: ' . $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Exibir uma categoria específica
     */
    public function show(int $id): JsonResponse
    {
        $category = Category::where('user_id', Auth::id())
            ->with(['keywords', 'parent', 'children.keywords'])
            ->findOrFail($id);

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

    /**
     * Atualizar uma categoria
     */
    public function update(Request $request, int $id): JsonResponse
    {
        $category = Category::where('user_id', Auth::id())->findOrFail($id);

        $validated = $request->validate([
            'name' => 'sometimes|required|string|max:100',
            'parent_id' => 'nullable|exists:categories,id',
            'type' => ['nullable', Rule::in(array_keys(Category::TYPES))],
            'description' => 'nullable|string',
            'color' => 'nullable|string|max:7',
            'icon' => 'nullable|string|max:50',
            'order' => 'nullable|integer',
            'is_active' => 'nullable|boolean',
            'keywords' => 'nullable|array',
            'keywords.*' => 'string|max:100',
        ]);

        // Verificar se parent_id pertence ao usuário e não é a própria categoria
        if (!empty($validated['parent_id'])) {
            if ($validated['parent_id'] == $id) {
                return response()->json([
                    'success' => false,
                    'message' => 'Uma categoria não pode ser pai de si mesma',
                ], 422);
            }
            Category::where('user_id', Auth::id())->findOrFail($validated['parent_id']);
        }

        $keywords = $validated['keywords'] ?? null;
        unset($validated['keywords']);

        DB::beginTransaction();
        try {
            $category->update($validated);

            // Se keywords foram fornecidas, sincronizar
            if ($keywords !== null) {
                $category->keywords()->delete();
                foreach ($keywords as $keyword) {
                    $category->keywords()->create([
                        'keyword' => trim($keyword),
                        'is_case_sensitive' => false,
                        'is_active' => true,
                    ]);
                }
            }

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Categoria atualizada com sucesso',
                'data' => $category->fresh()->load(['keywords', 'parent', 'children']),
            ]);

        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Erro ao atualizar categoria: ' . $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Deletar uma categoria (soft delete)
     */
    public function destroy(int $id): JsonResponse
    {
        $category = Category::where('user_id', Auth::id())->findOrFail($id);

        // Se tem filhas, mover para nível raiz
        if ($category->children()->exists()) {
            $category->children()->update(['parent_id' => null]);
        }

        $category->keywords()->delete();
        $category->delete();

        return response()->json([
            'success' => true,
            'message' => 'Categoria excluída com sucesso',
        ]);
    }

    /**
     * Adicionar palavra-chave a uma categoria
     */
    public function addKeyword(Request $request, int $id): JsonResponse
    {
        $category = Category::where('user_id', Auth::id())->findOrFail($id);

        $validated = $request->validate([
            'keyword' => 'required|string|max:100',
            'is_case_sensitive' => 'nullable|boolean',
        ]);

        $keyword = $category->keywords()->create([
            'keyword' => trim($validated['keyword']),
            'is_case_sensitive' => $validated['is_case_sensitive'] ?? false,
            'is_active' => true,
        ]);

        return response()->json([
            'success' => true,
            'message' => 'Palavra-chave adicionada com sucesso',
            'data' => $keyword,
        ], 201);
    }

    /**
     * Remover palavra-chave de uma categoria
     */
    public function removeKeyword(int $id, int $keywordId): JsonResponse
    {
        $category = Category::where('user_id', Auth::id())->findOrFail($id);
        $keyword = $category->keywords()->findOrFail($keywordId);
        $keyword->delete();

        return response()->json([
            'success' => true,
            'message' => 'Palavra-chave removida com sucesso',
        ]);
    }

    /**
     * Encontrar categoria por texto (usando palavras-chave)
     */
    public function matchByText(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'text' => 'required|string',
            'type' => ['nullable', Rule::in(array_keys(Category::TYPES))],
        ]);

        $text = $validated['text'];
        $textLower = strtolower($text);

        $query = CategoryKeyword::whereHas('category', function ($query) use ($validated) {
            $query->where('user_id', Auth::id())->where('is_active', true);
            if (!empty($validated['type'])) {
                $query->ofType($validated['type']);
            }
        })
            ->where('is_active', true)
            ->with('category');

        $keywords = $query->get();

        $matches = [];
        foreach ($keywords as $keyword) {
            $searchText = $keyword->is_case_sensitive ? $text : $textLower;
            $searchKeyword = $keyword->is_case_sensitive ? $keyword->keyword : strtolower($keyword->keyword);

            if (str_contains($searchText, $searchKeyword)) {
                $matches[] = [
                    'category' => $keyword->category,
                    'matched_keyword' => $keyword->keyword,
                ];
            }
        }

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

    /**
     * Reordenar categorias
     */
    public function reorder(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'orders' => 'required|array',
            'orders.*.id' => 'required|exists:categories,id',
            'orders.*.order' => 'required|integer',
        ]);

        DB::beginTransaction();
        try {
            foreach ($validated['orders'] as $orderData) {
                Category::where('user_id', Auth::id())
                    ->where('id', $orderData['id'])
                    ->update(['order' => $orderData['order']]);
            }
            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Ordem atualizada com sucesso',
            ]);

        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Erro ao reordenar categorias: ' . $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Categorizar transações em lote baseado em palavras-chave
     */
    public function categorizeBatch(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'only_uncategorized' => 'nullable|boolean',
            'transaction_ids' => 'nullable|array',
            'transaction_ids.*' => 'integer|exists:transactions,id',
        ]);

        $onlyUncategorized = $validated['only_uncategorized'] ?? true;
        $transactionIds = $validated['transaction_ids'] ?? null;

        // Buscar todas as categorias com keywords do usuário
        $categories = Category::where('user_id', Auth::id())
            ->whereNotNull('parent_id') // Apenas subcategorias
            ->with('keywords')
            ->where('is_active', true)
            ->get();

        // Construir mapa de keywords -> categoria
        $keywordMap = [];
        foreach ($categories as $category) {
            foreach ($category->keywords as $keyword) {
                if ($keyword->is_active) {
                    $keywordMap[strtoupper($keyword->keyword)] = $category->id;
                }
            }
        }

        if (empty($keywordMap)) {
            return response()->json([
                'success' => false,
                'message' => 'Nenhuma palavra-chave configurada nas categorias',
                'data' => [
                    'categorized' => 0,
                    'skipped' => 0,
                ]
            ]);
        }

        // Buscar transações para categorizar
        $query = \App\Models\Transaction::where('user_id', Auth::id());
        
        if ($onlyUncategorized) {
            $query->whereNull('category_id');
        }

        if ($transactionIds) {
            $query->whereIn('id', $transactionIds);
        }

        $transactions = $query->get();

        $categorized = 0;
        $skipped = 0;

        foreach ($transactions as $transaction) {
            // Usar description ou original_description
            $text = strtoupper($transaction->original_description ?? $transaction->description ?? '');
            
            $matched = false;
            foreach ($keywordMap as $keyword => $categoryId) {
                if (str_contains($text, $keyword)) {
                    $transaction->category_id = $categoryId;
                    $transaction->save();
                    $categorized++;
                    $matched = true;
                    break; // Usar primeira keyword que bater
                }
            }

            if (!$matched) {
                $skipped++;
            }
        }

        return response()->json([
            'success' => true,
            'message' => "Categorização em lote concluída",
            'data' => [
                'categorized' => $categorized,
                'skipped' => $skipped,
                'total_keywords' => count($keywordMap),
            ]
        ]);
    }

    /**
     * Preview da categorização em lote (sem salvar)
     */
    public function categorizeBatchPreview(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'only_uncategorized' => 'nullable|boolean',
            'preview_limit' => 'nullable|integer|min:1|max:100',
            'filters' => 'nullable|array',
            'filters.account_id' => 'nullable|integer',
            'filters.category_id' => 'nullable|integer',
            'filters.cost_center_id' => 'nullable|integer',
            'filters.type' => 'nullable|string|in:credit,debit',
            'filters.status' => 'nullable|string|in:pending,completed,cancelled',
            'filters.start_date' => 'nullable|date',
            'filters.end_date' => 'nullable|date',
            'filters.search' => 'nullable|string|max:255',
        ]);

        $onlyUncategorized = $validated['only_uncategorized'] ?? true;
        $previewLimit = $validated['preview_limit'] ?? 50;
        $filters = $validated['filters'] ?? [];

        // Buscar todas as categorias com keywords do usuário
        $categories = Category::where('user_id', Auth::id())
            ->whereNotNull('parent_id')
            ->with(['keywords', 'parent'])
            ->where('is_active', true)
            ->get();

        // Construir mapa de keywords -> categoria
        $keywordMap = [];
        $categoryNames = [];
        foreach ($categories as $category) {
            $categoryNames[$category->id] = ($category->parent ? $category->parent->name . ' > ' : '') . $category->name;
            foreach ($category->keywords as $keyword) {
                if ($keyword->is_active) {
                    $keywordMap[strtoupper($keyword->keyword)] = [
                        'category_id' => $category->id,
                        'category_name' => $categoryNames[$category->id],
                        'keyword' => $keyword->keyword,
                    ];
                }
            }
        }

        // Buscar transações com filtros aplicados
        $query = \App\Models\Transaction::where('user_id', Auth::id());
        
        if ($onlyUncategorized) {
            $query->whereNull('category_id');
        }

        // Aplicar filtros
        if (!empty($filters['account_id'])) {
            $query->where('account_id', $filters['account_id']);
        }
        if (!empty($filters['category_id'])) {
            $query->where('category_id', $filters['category_id']);
        }
        if (!empty($filters['cost_center_id'])) {
            $query->where('cost_center_id', $filters['cost_center_id']);
        }
        if (!empty($filters['type'])) {
            $query->where('type', $filters['type']);
        }
        if (!empty($filters['status'])) {
            $query->where('status', $filters['status']);
        }
        if (!empty($filters['start_date'])) {
            $query->where(function ($q) use ($filters) {
                $q->where('effective_date', '>=', $filters['start_date'])
                  ->orWhere(function ($q2) use ($filters) {
                      $q2->whereNull('effective_date')
                         ->where('planned_date', '>=', $filters['start_date']);
                  });
            });
        }
        if (!empty($filters['end_date'])) {
            $query->where(function ($q) use ($filters) {
                $q->where('effective_date', '<=', $filters['end_date'])
                  ->orWhere(function ($q2) use ($filters) {
                      $q2->whereNull('effective_date')
                         ->where('planned_date', '<=', $filters['end_date']);
                  });
            });
        }
        if (!empty($filters['search'])) {
            $search = $filters['search'];
            $query->where(function ($q) use ($search) {
                $q->where('description', 'like', "%{$search}%")
                  ->orWhere('original_description', 'like', "%{$search}%")
                  ->orWhere('reference', 'like', "%{$search}%")
                  ->orWhere('notes', 'like', "%{$search}%");
            });
        }

        $allTransactions = $query->get();

        $preview = [];
        $wouldCategorize = 0;
        $wouldSkip = 0;
        $transactionIds = [];

        foreach ($allTransactions as $transaction) {
            $text = strtoupper($transaction->original_description ?? $transaction->description ?? '');
            
            $matched = null;
            foreach ($keywordMap as $keyword => $info) {
                if (str_contains($text, $keyword)) {
                    $matched = $info;
                    break;
                }
            }

            if ($matched) {
                $wouldCategorize++;
                $transactionIds[] = $transaction->id;
                // Só adiciona preview até o limite
                if (count($preview) < $previewLimit) {
                    $preview[] = [
                        'transaction_id' => $transaction->id,
                        'description' => $transaction->description,
                        'amount' => $transaction->amount ?? $transaction->planned_amount,
                        'matched_keyword' => $matched['keyword'],
                        'category_id' => $matched['category_id'],
                        'category_name' => $matched['category_name'],
                    ];
                }
            } else {
                $wouldSkip++;
            }
        }

        // Contar total sem categoria (com filtros)
        $totalUncategorized = $allTransactions->whereNull('category_id')->count();

        // Preparar lista de transações para seleção
        $transactions = $allTransactions->take(100)->map(function ($t) {
            return [
                'id' => $t->id,
                'description' => $t->description,
                'amount' => $t->amount ?? $t->planned_amount,
                'type' => $t->type,
                'effective_date' => $t->effective_date?->format('d/m/Y'),
                'planned_date' => $t->planned_date?->format('d/m/Y'),
            ];
        })->values();

        return response()->json([
            'success' => true,
            'data' => [
                'preview' => $preview,
                'would_categorize' => $wouldCategorize,
                'would_skip' => $wouldSkip,
                'total_uncategorized' => $totalUncategorized,
                'total_keywords' => count($keywordMap),
                'total_filtered' => $allTransactions->count(),
                'transaction_ids' => $transactionIds,
                'transactions' => $transactions,
            ]
        ]);
    }

    /**
     * Categorização em lote manual - aplicar categoria/centro de custo selecionados
     */
    public function categorizeBatchManual(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'category_id' => 'nullable|integer|exists:categories,id',
            'cost_center_id' => 'nullable|integer|exists:cost_centers,id',
            'filters' => 'nullable|array',
            'filters.account_id' => 'nullable|integer',
            'filters.type' => 'nullable|string|in:credit,debit',
            'filters.status' => 'nullable|string|in:pending,completed,cancelled',
            'filters.start_date' => 'nullable|date',
            'filters.end_date' => 'nullable|date',
            'filters.search' => 'nullable|string|max:255',
            'add_keyword' => 'nullable|boolean',
            'transaction_ids' => 'nullable|array',
            'transaction_ids.*' => 'integer',
        ]);

        $categoryId = $validated['category_id'] ?? null;
        $costCenterId = $validated['cost_center_id'] ?? null;
        $filters = $validated['filters'] ?? [];
        $addKeyword = $validated['add_keyword'] ?? false;
        $transactionIds = $validated['transaction_ids'] ?? null;

        // Verificar se pelo menos uma opção foi selecionada
        if (!$categoryId && !$costCenterId) {
            return response()->json([
                'success' => false,
                'message' => 'Selecione pelo menos uma categoria ou centro de custo',
            ], 400);
        }

        // Verificar se a categoria pertence ao usuário
        if ($categoryId) {
            $category = Category::where('id', $categoryId)
                ->where('user_id', Auth::id())
                ->first();
            if (!$category) {
                return response()->json([
                    'success' => false,
                    'message' => 'Categoria não encontrada',
                ], 404);
            }
        }

        // Verificar se o centro de custo pertence ao usuário
        if ($costCenterId) {
            $costCenter = \App\Models\CostCenter::where('id', $costCenterId)
                ->where('user_id', Auth::id())
                ->first();
            if (!$costCenter) {
                return response()->json([
                    'success' => false,
                    'message' => 'Centro de custo não encontrado',
                ], 404);
            }
        }

        // Construir query - usar IDs se fornecidos, senão usar filtros
        $query = \App\Models\Transaction::where('user_id', Auth::id());

        if (!empty($transactionIds)) {
            // Usar IDs específicos
            $query->whereIn('id', $transactionIds);
        } else {
            // Usar filtros
            if (!empty($filters['account_id'])) {
                $query->where('account_id', $filters['account_id']);
            }
            if (!empty($filters['type'])) {
                $query->where('type', $filters['type']);
            }
            if (!empty($filters['status'])) {
                $query->where('status', $filters['status']);
            }
            if (!empty($filters['start_date'])) {
                $query->where(function ($q) use ($filters) {
                    $q->where('effective_date', '>=', $filters['start_date'])
                      ->orWhere(function ($q2) use ($filters) {
                          $q2->whereNull('effective_date')
                             ->where('planned_date', '>=', $filters['start_date']);
                      });
                });
            }
            if (!empty($filters['end_date'])) {
                $query->where(function ($q) use ($filters) {
                    $q->where('effective_date', '<=', $filters['end_date'])
                      ->orWhere(function ($q2) use ($filters) {
                          $q2->whereNull('effective_date')
                             ->where('planned_date', '<=', $filters['end_date']);
                      });
                });
            }
            if (!empty($filters['search'])) {
                $search = $filters['search'];
                $query->where(function ($q) use ($search) {
                    $q->where('description', 'like', "%{$search}%")
                      ->orWhere('original_description', 'like', "%{$search}%")
                      ->orWhere('reference', 'like', "%{$search}%")
                      ->orWhere('notes', 'like', "%{$search}%");
                });
            }
        }

        // Atualizar transações
        $updateData = [];
        if ($categoryId) {
            $updateData['category_id'] = $categoryId;
        }
        if ($costCenterId) {
            $updateData['cost_center_id'] = $costCenterId;
        }

        $updated = $query->update($updateData);

        // Adicionar keyword se solicitado e houver termo de busca
        $keywordAdded = false;
        $keywordText = null;
        if ($addKeyword && !empty($filters['search']) && strlen(trim($filters['search'])) >= 2) {
            $keywordText = trim($filters['search']);
            
            // Adicionar keyword à categoria (se selecionada)
            if ($categoryId) {
                $existingCategoryKeyword = \App\Models\CategoryKeyword::where('category_id', $categoryId)
                    ->whereRaw('UPPER(keyword) = ?', [strtoupper($keywordText)])
                    ->first();
                
                if (!$existingCategoryKeyword) {
                    \App\Models\CategoryKeyword::create([
                        'category_id' => $categoryId,
                        'keyword' => $keywordText,
                        'is_case_sensitive' => false,
                        'is_active' => true,
                    ]);
                    $keywordAdded = true;
                }
            }
            
            // Adicionar keyword ao centro de custo (se selecionado)
            if ($costCenterId) {
                $existingCostCenterKeyword = \App\Models\CostCenterKeyword::where('cost_center_id', $costCenterId)
                    ->whereRaw('UPPER(keyword) = ?', [strtoupper($keywordText)])
                    ->first();
                
                if (!$existingCostCenterKeyword) {
                    \App\Models\CostCenterKeyword::create([
                        'cost_center_id' => $costCenterId,
                        'keyword' => $keywordText,
                        'is_case_sensitive' => false,
                        'is_active' => true,
                    ]);
                    $keywordAdded = true;
                }
            }
        }

        return response()->json([
            'success' => true,
            'message' => 'Categorização em lote concluída',
            'data' => [
                'updated' => $updated,
                'keyword_added' => $keywordAdded,
                'keyword_text' => $keywordText,
            ]
        ]);
    }
}
