<?php

namespace App\Controllers\Api;

use App\Libraries\AuditLogger;
use App\Libraries\ResponseHelper;
use App\Libraries\UuidHelper;
use App\Models\FinanceAttachmentModel;
use App\Models\FinanceCategoryModel;
use App\Models\FinanceTransactionModel;

class FinanceController extends BaseApiController
{
    private FinanceTransactionModel $model;

    public function initController(
        \CodeIgniter\HTTP\RequestInterface $request,
        \CodeIgniter\HTTP\ResponseInterface $response,
        \Psr\Log\LoggerInterface $logger
    ): void {
        parent::initController($request, $response, $logger);
        $this->model = $this->scopedModel(new FinanceTransactionModel());
    }

    public function index()
    {
        if ($err = $this->requirePermission('view_finance')) return $err;

        $type     = $this->request->getGet('type');
        $category = $this->request->getGet('category_id');
        $from     = $this->request->getGet('date_from');
        $to       = $this->request->getGet('date_to');
        $search   = $this->request->getGet('search');

        if ($type)     $this->model->where('type', $type);
        if ($category) $this->model->where('category_id', $category);
        if ($from)     $this->model->where('transaction_date >=', $from);
        if ($to)       $this->model->where('transaction_date <=', $to);
        if ($search) {
            $s = $this->model->db->escapeLikeString($search);
            $this->model->groupStart()->like('description', $s)->orLike('reference', $s)->groupEnd();
        }

        $this->model->orderBy('transaction_date', 'DESC');

        $result         = $this->model->scopedPaginate($this->getPerPage());
        $result['data'] = array_map([$this, 'format'], $result['data']);

        return ResponseHelper::paginated($result);
    }

    public function create()
    {
        if ($err = $this->requirePermission('add_finance')) return $err;

        $data = $this->getJson();
        $v    = service('validation');
        $v->setRules([
            'type'             => 'required|in_list[income,expense]',
            'amount'           => 'required|decimal',
            'transaction_date' => 'required|valid_date',
        ]);

        if (!$v->run($data)) {
            return ResponseHelper::validationError($v->getErrors());
        }

        $user = $this->currentUser();
        $uuid = UuidHelper::generate();
        $this->model->insert([
            'uuid'             => $uuid,
            'church_id'        => $this->churchId(),
            'category_id'      => $data['category_id'] ?? null,
            'recorded_by'      => $user['id'] ?? null,
            'type'             => $data['type'],
            'amount'           => $data['amount'],
            'description'      => $data['description'] ?? null,
            'reference'        => $data['reference'] ?? null,
            'transaction_date' => $data['transaction_date'],
        ]);

        $tx = $this->model->findByUuid($uuid);
        AuditLogger::log('finance.created', 'finance_transactions', $uuid, null, $tx);

        return ResponseHelper::created($this->format($tx));
    }

    public function show(string $uuid)
    {
        if ($err = $this->requirePermission('view_finance')) return $err;

        $tx = $this->model->findByUuid($uuid);
        if (!$tx) return ResponseHelper::notFound();

        $attachModel = new FinanceAttachmentModel();
        $tx['attachments'] = $attachModel->where('transaction_id', $tx['id'])->findAll();

        return ResponseHelper::success($this->format($tx));
    }

    public function update(string $uuid)
    {
        if ($err = $this->requirePermission('edit_finance')) return $err;

        $tx = $this->model->findByUuid($uuid);
        if (!$tx) return ResponseHelper::notFound();

        $data    = $this->getJson();
        $allowed = ['category_id', 'type', 'amount', 'description', 'reference', 'transaction_date'];
        $update  = array_intersect_key($data, array_flip($allowed));

        $old = $tx;
        $this->model->update($tx['id'], $update);
        $new = $this->model->findByUuid($uuid);

        AuditLogger::log('finance.updated', 'finance_transactions', $uuid, $old, $new);

        return ResponseHelper::success($this->format($new));
    }

    public function delete(string $uuid)
    {
        if ($err = $this->requirePermission('delete_finance')) return $err;

        $tx = $this->model->findByUuid($uuid);
        if (!$tx) return ResponseHelper::notFound();

        $this->model->delete($tx['id']);
        AuditLogger::log('finance.deleted', 'finance_transactions', $uuid, $tx, null);

        return ResponseHelper::success(null);
    }

    public function summary()
    {
        if ($err = $this->requirePermission('view_finance')) return $err;

        $from    = $this->request->getGet('date_from');
        $to      = $this->request->getGet('date_to');
        $summary = (new FinanceTransactionModel())->getSummary($this->churchId(), $from, $to);

        return ResponseHelper::success($summary);
    }

    public function uploadAttachment()
    {
        if ($err = $this->requirePermission('add_finance')) return $err;

        $file = $this->request->getFile('file');

        if (!$file || !$file->isValid()) {
            return ResponseHelper::error('No valid file uploaded', 422);
        }

        $allowed = ['application/pdf', 'image/jpeg', 'image/jpg', 'image/png'];
        if (!in_array($file->getMimeType(), $allowed, true)) {
            return ResponseHelper::error('Only PDF, JPG, and PNG files are allowed', 422);
        }

        if ($file->getSize() > 5 * 1024 * 1024) {
            return ResponseHelper::error('File size must not exceed 5 MB', 422);
        }

        $db        = \Config\Database::connect();
        $churchRow = $db->table('churches')->where('id', $this->churchId())->get()->getRowArray();
        $churchUuid = $churchRow['uuid'] ?? $this->churchId();

        $yearMonth = date('Y/m');
        $destDir   = WRITEPATH . 'uploads/finance/' . $churchUuid . '/' . $yearMonth;

        if (!is_dir($destDir)) {
            mkdir($destDir, 0755, true);
        }

        $newName = $file->getRandomName();
        $file->move($destDir, $newName);

        $relativePath = 'uploads/finance/' . $churchUuid . '/' . $yearMonth . '/' . $newName;

        $txId = $this->request->getPost('transaction_id');
        $txDbId = null;
        if ($txId) {
            $txRow = $this->model->findByUuid($txId);
            $txDbId = $txRow['id'] ?? null;
        }

        $attachModel = new FinanceAttachmentModel();
        $attachModel->insert([
            'transaction_id' => $txDbId,
            'church_id'      => $this->churchId(),
            'file_path'      => $relativePath,
            'original_name'  => $file->getClientName(),
            'mime_type'      => $file->getMimeType(),
            'file_size'      => $file->getSize(),
        ]);

        return ResponseHelper::created(['file_path' => $relativePath]);
    }

    public function categories()
    {
        if ($err = $this->requirePermission('view_finance')) return $err;

        $income  = $this->scopedModel(new FinanceCategoryModel())->where('type', 'income')->findAll();
        $expense = $this->scopedModel(new FinanceCategoryModel())->where('type', 'expense')->findAll();

        return ResponseHelper::success([
            'income'  => array_map(fn($c) => ['uuid' => $c['uuid'], 'name' => $c['name']], $income),
            'expense' => array_map(fn($c) => ['uuid' => $c['uuid'], 'name' => $c['name']], $expense),
        ]);
    }

    private function format(array $tx): array
    {
        return [
            'uuid'             => $tx['uuid'],
            'type'             => $tx['type'],
            'amount'           => (float) $tx['amount'],
            'description'      => $tx['description'],
            'reference'        => $tx['reference'],
            'transaction_date' => $tx['transaction_date'],
            'category_id'      => $tx['category_id'],
            'created_at'       => $tx['created_at'],
            'attachments'      => $tx['attachments'] ?? [],
        ];
    }
}
