<?php

use Carbon\Carbon;
use Firefly\Helper\Controllers\ChartInterface;
use Firefly\Storage\Account\AccountRepositoryInterface;

/**
 * Class ChartController
 */
class ChartController extends BaseController
{

    protected $_chart;
    protected $_accounts;


    /**
     * @param ChartInterface             $chart
     * @param AccountRepositoryInterface $accounts
     */
    public function __construct(ChartInterface $chart, AccountRepositoryInterface $accounts)
    {
        $this->_chart    = $chart;
        $this->_accounts = $accounts;
    }

    /**
     * This method takes a budget, all limits and all their repetitions and displays three numbers per repetition:
     * the amount of money in the repetition (represented as "an envelope"), the amount spent and the spent percentage.
     *
     * @param Budget $budget
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function budgetDefault(\Budget $budget)
    {
        $expense  = [];
        $left     = [];
        $envelope = [];
        // get all limit repetitions for this budget.
        /** @var \Limit $limit */
        foreach ($budget->limits as $limit) {
            /** @var \LimitRepetition $rep */
            foreach ($limit->limitrepetitions as $rep) {
                // get the amount of money spent in this period on this budget.
                $spentInRep = $rep->amount - $rep->left();
                $pct        = round((floatval($spentInRep) / floatval($limit->amount)) * 100, 2);
                $name       = $rep->periodShow();
                $envelope[] = [$name, floatval($limit->amount)];
                $expense[]  = [$name, floatval($spentInRep)];
                $left[]     = [$name, $pct];
            }
        }

        $return = [
            'chart_title' => 'Overview for budget ' . $budget->name,
            'subtitle'    => 'All envelopes',
            'series'      => [
                [
                    'type'  => 'line',
                    'yAxis' => 1,
                    'name'  => 'Amount in envelope',
                    'data'  => $envelope
                ],
                [
                    'type' => 'column',
                    'name' => 'Expenses in envelope',
                    'data' => $expense
                ],
                [
                    'type'  => 'line',
                    'yAxis' => 1,
                    'name'  => 'Spent percentage for envelope',
                    'data'  => $left
                ]


            ]
        ];

        return Response::json($return);
    }

    /**
     * This method takes a single limit repetition (so a single "envelope") and displays the amount of money spent
     * per day and subsequently how much money is left.
     *
     * @param LimitRepetition $rep
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function budgetLimit(\LimitRepetition $rep)
    {
        $budget             = $rep->limit->budget;
        $current            = clone $rep->startdate;
        $expense            = [];
        $leftInLimit        = [];
        $currentLeftInLimit = floatval($rep->limit->amount);
        while ($current <= $rep->enddate) {
            $spent              = $this->_chart->spentOnDay($budget, $current);
            $spent              = floatval($spent) == 0 ? null : floatval($spent);
            $entry              = [$current->timestamp * 1000, $spent];
            $expense[]          = $entry;
            $currentLeftInLimit = $currentLeftInLimit - $spent;
            $leftInLimit[]      = [$current->timestamp * 1000, $currentLeftInLimit];
            $current->addDay();
        }

        $return = [
            'chart_title' => 'Overview for budget ' . $budget->name,
            'subtitle'    =>
                'Between ' . $rep->startdate->format('M jS, Y') . ' and ' . $rep->enddate->format('M jS, Y'),
            'series'      => [
                [
                    'type'  => 'column',
                    'name'  => 'Expenses per day',
                    'yAxis' => 1,
                    'data'  => $expense
                ],
                [
                    'type' => 'line',
                    'name' => 'Left in envelope',
                    'data' => $leftInLimit
                ]

            ]
        ];

        return Response::json($return);
    }

    /**
     * This method takes a budget and gets all transactions in it which haven't got an envelope (limit).
     *
     * Usually this means that very old and unorganized or very NEW transactions get displayed; there was never an
     * envelope or it hasn't been created (yet).
     *
     *
     * @param Budget $budget
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function budgetNoLimits(\Budget $budget)
    {
        /*
         * We can go about this two ways. Either we find all transactions which definitely are IN an envelope
         * and exclude them or we search for transactions outside of the range of any of the envelopes we have.
         *
         * Since either is shitty we go with the first one because it's easier to build.
         */
        $inRepetitions = $this->_chart->allJournalsInBudgetEnvelope($budget);

        /*
         * With this set of id's, we can search for all journals NOT in that set.
         * BUT they have to be in the budget (duh).
         */
        $set = $this->_chart->journalsNotInSet($budget, $inRepetitions);
        /*
         * Next step: get all transactions for those journals.
         */
        $transactions = $this->_chart->transactionsByJournals($set);


        /*
         *  this set builds the chart:
         */
        $expense = [];

        foreach ($transactions as $t) {
            $date      = new Carbon($t->date);
            $expense[] = [$date->timestamp * 1000, floatval($t->aggregate)];
        }
        $return = [
            'chart_title' => 'Overview for ' . $budget->name,
            'subtitle'    => 'Not organized by an envelope',
            'series'      => [
                [
                    'type' => 'column',
                    'name' => 'Expenses per day',
                    'data' => $expense
                ]

            ]
        ];
        return Response::json($return);
    }

    /**
     * This method gets all transactions within a budget within the period set by the current session
     * start and end date. It also includes any envelopes which might exist within this period.
     *
     * @param Budget $budget
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function budgetSession(\Budget $budget)
    {
        $series = [];
        $end    = clone Session::get('end');
        $start  = clone Session::get('start');



        /*
         * Expenses per day in the session's period. That's easy.
         */
        $expense = [];
        $current = clone Session::get('start');
        while ($current <= $end) {
            $spent     = $this->_chart->spentOnDay($budget, $current);
            $spent     = floatval($spent) == 0 ? null : floatval($spent);
            $expense[] = [$current->timestamp * 1000, $spent];
            $current->addDay();
        }

        $series[] = [
            'type' => 'column',
            'name' => 'Expenses per day',
            'data' => $expense
        ];
        unset($expense, $spent, $current);

        /*
         * Find all limit repetitions (for this budget) between start and end. This is
         * quite a complex query.
         */
        $reps = $this->_chart->limitsInRange($budget, $start, $end);

        /*
         * For each limitrepetition we create a serie that contains the amount left in
         * the limitrepetition for its entire date-range. Entries are only actually included when they
         * fall into the charts date range.
         *
         * So example: we have a session date from Jan 15 to Jan 30. The limitrepetition starts at 1 Jan until 1 Feb.
         *
         * We loop from 1 Jan to 1 Feb but only include Jan 15 / Jan 30. But we do keep count of the amount outside
         * of these dates because otherwise the line might be wrong.
         */
        /** @var \LimitRepetition $repetition */
        foreach ($reps as $repetition) {
            $limitAmount = $repetition->limit->amount;

            // create a serie for the repetition.
            $currentSerie = [
                'type'  => 'spline',
                'id'    => 'rep-' . $repetition->id,
                'yAxis' => 1,
                'name'  => 'Envelope #'.$repetition->id.' in ' . $repetition->periodShow(),
                'data'  => []
            ];
            $current      = clone $repetition->startdate;
            while ($current <= $repetition->enddate) {
                if ($current >= $start && $current <= $end) {
                    // spent on limit:
                    $spentSoFar  = $this->_chart->spentOnLimitRepetitionBetweenDates(
                        $repetition, $repetition->startdate, $current
                    );
                    $leftInLimit = floatval($limitAmount) - floatval($spentSoFar);

                    $currentSerie['data'][] = [$current->timestamp * 1000, $leftInLimit];
                }
                $current->addDay();
            }

            // do something here.
            $series[] = $currentSerie;
        }

        $return = [
            'chart_title' => 'Overview for budget ' . $budget->name,
            'subtitle'    =>
                'Between ' . Session::get('start')->format('M jS, Y') . ' and ' . Session::get('end')->format(
                    'M jS, Y'
                ),
            'series'      => $series
        ];

        return Response::json($return);

    }

    /**
     * @param Category $category
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function categoryShowChart(Category $category)
    {
        $start = Session::get('start');
        $end   = Session::get('end');
        $range = Session::get('range');

        $serie = $this->_chart->categoryShowChart($category, $range, $start, $end);
        $data  = [
            'chart_title' => $category->name,
            'subtitle'    => '<a href="' . route('categories.show', [$category->id]) . '">View more</a>',
            'series'      => $serie
        ];

        return Response::json($data);


    }

    /**
     * @param Account $account
     *
     * @return mixed
     */
    public function homeAccount(Account $account = null)
    {
        // get preferences and accounts (if necessary):
        $start = Session::get('start');
        $end   = Session::get('end');

        if (is_null($account)) {
            // get, depending on preferences:
            /** @var  \Firefly\Helper\Preferences\PreferencesHelperInterface $prefs */
            $prefs = \App::make('Firefly\Helper\Preferences\PreferencesHelperInterface');
            $pref  = $prefs->get('frontpageAccounts', []);

            /** @var \Firefly\Storage\Account\AccountRepositoryInterface $acct */
            $acct     = \App::make('Firefly\Storage\Account\AccountRepositoryInterface');
            $accounts = $acct->getByIds($pref->data);
        } else {
            $accounts = [$account];
        }
        // loop and get array data.

        $url  = count($accounts) == 1 && is_array($accounts)
            ? '<a href="' . route('accounts.show', [$account->id]) . '">View more</a>'
            :
            '<a href="' . route('accounts.index') . '">View more</a>';
        $data = [
            'chart_title' => count($accounts) == 1 ? $accounts[0]->name : 'All accounts',
            'subtitle'    => $url,
            'series'      => []
        ];

        foreach ($accounts as $account) {
            $data['series'][] = $this->_chart->account($account, $start, $end);
        }

        return Response::json($data);
    }

    /**
     * @param $name
     * @param $day
     * @param $month
     * @param $year
     *
     * @return $this
     */
    public function homeAccountInfo($name, $day, $month, $year)
    {
        $account = $this->_accounts->findByName($name);

        $date   = Carbon::createFromDate($year, $month, $day);
        $result = $this->_chart->accountDailySummary($account, $date);

        return View::make('charts.info')->with('rows', $result['rows'])->with('sum', $result['sum'])->with(
            'account', $account
        );
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function homeBudgets()
    {
        $start = \Session::get('start');

        return Response::json($this->_chart->budgets($start));
    }

    /**
     * @return \Illuminate\Http\JsonResponse
     */
    public function homeCategories()
    {
        $start = Session::get('start');
        $end   = Session::get('end');

        return Response::json($this->_chart->categories($start, $end));


    }
}