<?php

namespace Modules\Accounting\Controllers;

use App\Controllers\BaseController;
use App\Models\BankAccountModel;
use App\Models\BankTransferModel;
use App\Models\CashAccountModel;
use Modules\Accounting\Services\BankTransferService;

class BankTransferController extends BaseController
{
    protected BankTransferModel $transfers;
    protected BankTransferService $service;
    protected BankAccountModel $banks;
    protected CashAccountModel $cash;

    public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
    {
        parent::initController($request, $response, $logger);
        $this->transfers = new BankTransferModel();
        $this->service   = new BankTransferService();
        $this->banks     = new BankAccountModel();
        $this->cash      = new CashAccountModel();
    }

    public function index()
    {
        $search = trim((string) $this->request->getGet('q'));
        $status = $this->request->getGet('status') ?: null;

        $transfers = $this->transfers
            ->scopeForList($search ?: null, $status)
            ->orderBy('bank_transfers.transfer_date', 'DESC')
            ->orderBy('bank_transfers.id', 'DESC')
            ->findAll();

        $transfers = array_map(fn (array $t) => $this->enrichTransfer($t), $transfers);

        return view('Modules\Accounting\Views\bank_transfers\index', array_merge($this->baseViewData(), [
            'title'     => 'Bank Transfers',
            'transfers' => $transfers,
            'filters'   => compact('search', 'status'),
        ]));
    }

    public function createForm()
    {
        return view('Modules\Accounting\Views\bank_transfers\create', array_merge($this->baseViewData(), [
            'title'         => 'New Transfer',
            'bankAccounts'  => $this->banks->getActive(),
            'cashAccounts'  => $this->cash->getActive(),
        ]));
    }

    public function store()
    {
        if (! $this->validate([
            'from_type'     => 'required|in_list[bank,cash]',
            'from_id'       => 'required|is_natural_no_zero',
            'to_type'       => 'required|in_list[bank,cash]',
            'to_id'         => 'required|is_natural_no_zero',
            'transfer_date' => 'required|valid_date',
            'amount'        => 'required|decimal',
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $result = $this->service->create($this->request->getPost(), (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->back()->withInput()->with('errors', $result['errors']);
        }

        return redirect()->to('/accounting/bank-transfers')->with('success', 'Transfer created.');
    }

    public function show(int $id)
    {
        $transfer = $this->transfers->find($id);
        if (! $transfer) {
            return redirect()->to('/accounting/bank-transfers')->with('error', 'Transfer not found.');
        }

        return view('Modules\Accounting\Views\bank_transfers\show', array_merge($this->baseViewData(), [
            'title'    => 'Transfer ' . $transfer['number'],
            'transfer' => $this->enrichTransfer($transfer),
        ]));
    }

    public function editForm(int $id)
    {
        $transfer = $this->transfers->find($id);
        if (! $transfer) {
            return redirect()->to('/accounting/bank-transfers')->with('error', 'Transfer not found.');
        }
        if ($transfer['status'] !== 'draft') {
            return redirect()->to('/accounting/bank-transfers/' . $id)->with('error', 'Only draft transfers can be edited.');
        }

        return view('Modules\Accounting\Views\bank_transfers\edit', array_merge($this->baseViewData(), [
            'title'        => 'Edit Transfer',
            'transfer'     => $transfer,
            'bankAccounts' => $this->banks->getActive(),
            'cashAccounts' => $this->cash->getActive(),
        ]));
    }

    public function update(int $id)
    {
        if (! $this->validate([
            'from_type'     => 'required|in_list[bank,cash]',
            'from_id'       => 'required|is_natural_no_zero',
            'to_type'       => 'required|in_list[bank,cash]',
            'to_id'         => 'required|is_natural_no_zero',
            'transfer_date' => 'required|valid_date',
            'amount'        => 'required|decimal',
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $result = $this->service->update($id, $this->request->getPost(), (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->back()->withInput()->with('errors', $result['errors']);
        }

        return redirect()->to('/accounting/bank-transfers')->with('success', 'Transfer updated.');
    }

    public function post(int $id)
    {
        $result = $this->service->post($id, (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->back()->with('error', $result['error']);
        }

        return redirect()->to('/accounting/bank-transfers/' . $id)->with('success', 'Transfer posted.');
    }

    public function destroy(int $id)
    {
        $result = $this->service->delete($id, (int) $this->session->get('user_id'));
        if (! $result['success']) {
            return redirect()->to('/accounting/bank-transfers')->with('error', $result['error']);
        }

        return redirect()->to('/accounting/bank-transfers')->with('success', 'Transfer deleted.');
    }

    protected function enrichTransfer(array $transfer): array
    {
        $transfer['from_label'] = $this->sideLabel($transfer['from_type'], (int) $transfer['from_id']);
        $transfer['to_label']   = $this->sideLabel($transfer['to_type'], (int) $transfer['to_id']);

        return $transfer;
    }

    protected function sideLabel(string $type, int $id): string
    {
        if ($type === 'bank') {
            $row = $this->banks->find($id);

            return $row ? ($row['code'] . ' · ' . $row['name'] . ' (Bank)') : 'Bank #' . $id;
        }
        if ($type === 'cash') {
            $row = $this->cash->find($id);

            return $row ? ($row['code'] . ' · ' . $row['name'] . ' (Cash)') : 'Cash #' . $id;
        }

        return '#';
    }
}
