<?php namespace App\Http\Controllers;

use Auth;
use Artisan;
use Cache;
use Config;
use DB;
use Exception;
use Input;
use Utils;
use View;
use Event;
use Session;
use Cookie;
use Response;
use Redirect;
use App\Models\User;
use App\Models\Account;
use App\Models\Industry;
use App\Ninja\Mailers\Mailer;
use App\Ninja\Repositories\AccountRepository;
use App\Events\UserSettingsChanged;
use App\Services\EmailService;

class AppController extends BaseController
{
    protected $accountRepo;
    protected $mailer;
    protected $emailService;

    public function __construct(AccountRepository $accountRepo, Mailer $mailer, EmailService $emailService)
    {
        parent::__construct();

        $this->accountRepo = $accountRepo;
        $this->mailer = $mailer;
        $this->emailService = $emailService;
    }

    public function showSetup()
    {
        if (Utils::isNinjaProd() || (Utils::isDatabaseSetup() && Account::count() > 0)) {
            return Redirect::to('/');
        }

        return View::make('setup');
    }

    public function doSetup()
    {
        if (Utils::isNinjaProd()) {
            return Redirect::to('/');
        }

        $valid = false;
        $test = Input::get('test');

        $app = Input::get('app');
        $app['key'] = env('APP_KEY') ?: str_random(RANDOM_KEY_LENGTH);
        $app['debug'] = Input::get('debug') ? 'true' : 'false';

        $database = Input::get('database');
        $dbType = 'mysql'; // $database['default'];
        $database['connections'] = [$dbType => $database['type']];

        $mail = Input::get('mail');
        $email = $mail['username'];
        $mail['from']['address'] = $email;

        if ($test == 'mail') {
            return self::testMail($mail);
        }

        $valid = self::testDatabase($database);

        if ($test == 'db') {
            return $valid === true ? 'Success' : $valid;
        } elseif (!$valid) {
            return Redirect::to('/setup')->withInput();
        }
        
        if (Utils::isDatabaseSetup() && Account::count() > 0) {
            return Redirect::to('/');
        }

        $config = "APP_ENV=production\n".
                    "APP_DEBUG={$app['debug']}\n".
                    "APP_URL={$app['url']}\n".
                    "APP_KEY={$app['key']}\n\n".
                    "DB_TYPE={$dbType}\n".
                    "DB_HOST={$database['type']['host']}\n".
                    "DB_DATABASE={$database['type']['database']}\n".
                    "DB_USERNAME={$database['type']['username']}\n".
                    "DB_PASSWORD={$database['type']['password']}\n\n".
                    "MAIL_DRIVER={$mail['driver']}\n".
                    "MAIL_PORT={$mail['port']}\n".
                    "MAIL_ENCRYPTION={$mail['encryption']}\n".
                    "MAIL_HOST={$mail['host']}\n".
                    "MAIL_USERNAME={$mail['username']}\n".
                    "MAIL_FROM_NAME={$mail['from']['name']}\n".
                    "MAIL_PASSWORD={$mail['password']}\n\n".
                    "PHANTOMJS_CLOUD_KEY='a-demo-key-with-low-quota-per-ip-address'";

        // Write Config Settings
        $fp = fopen(base_path()."/.env", 'w');
        fwrite($fp, $config);
        fclose($fp);

        // == DB Migrate & Seed == //
        // Artisan::call('migrate:rollback', array('--force' => true)); // Debug Purposes
        Artisan::call('migrate', array('--force' => true));
        if (Industry::count() == 0) {
            Artisan::call('db:seed', array('--force' => true));
        }
        Cache::flush();
        Artisan::call('optimize', array('--force' => true));
        
        $firstName = trim(Input::get('first_name'));
        $lastName = trim(Input::get('last_name'));
        $email = trim(strtolower(Input::get('email')));
        $password = trim(Input::get('password'));
        $account = $this->accountRepo->create($firstName, $lastName, $email, $password);
        $user = $account->users()->first();

        return Redirect::to('/login');
    }

    public function updateSetup()
    {
        if (Utils::isNinjaProd()) {
            return Redirect::to('/');
        }

        if (!Auth::check() && Utils::isDatabaseSetup() && Account::count() > 0) {
            return Redirect::to('/');
        }

        if ( ! $canUpdateEnv = @fopen(base_path()."/.env", 'w')) {
            Session::flash('error', 'Warning: Permission denied to write to .env config file, try running <code>sudo chown www-data:www-data /path/to/ninja/.env</code>');
            return Redirect::to('/settings/system_settings');
        }

        $app = Input::get('app');
        $db = Input::get('database');
        $mail = Input::get('mail');

        $_ENV['APP_URL'] = $app['url'];
        $_ENV['APP_DEBUG'] = Input::get('debug') ? 'true' : 'false';

        $_ENV['DB_TYPE'] = 'mysql'; // $db['default'];
        $_ENV['DB_HOST'] = $db['type']['host'];
        $_ENV['DB_DATABASE'] = $db['type']['database'];
        $_ENV['DB_USERNAME'] = $db['type']['username'];
        $_ENV['DB_PASSWORD'] = $db['type']['password'];
        
        if ($mail) {
            $_ENV['MAIL_DRIVER'] = $mail['driver'];
            $_ENV['MAIL_PORT'] = $mail['port'];
            $_ENV['MAIL_ENCRYPTION'] = $mail['encryption'];
            $_ENV['MAIL_HOST'] = $mail['host'];
            $_ENV['MAIL_USERNAME'] = $mail['username'];
            $_ENV['MAIL_FROM_NAME'] = $mail['from']['name'];
            $_ENV['MAIL_PASSWORD'] = $mail['password'];
            $_ENV['MAIL_FROM_ADDRESS'] = $mail['username'];
        }

        $config = '';
        foreach ($_ENV as $key => $val) {
            $config .= "{$key}={$val}\n";
        }

        $fp = fopen(base_path()."/.env", 'w');
        fwrite($fp, $config);
        fclose($fp);

        Session::flash('message', trans('texts.updated_settings'));
        return Redirect::to('/settings/system_settings');
    }

    private function testDatabase($database)
    {
        $dbType = 'mysql'; // $database['default'];
        Config::set('database.default', $dbType);
        foreach ($database['connections'][$dbType] as $key => $val) {
            Config::set("database.connections.{$dbType}.{$key}", $val);
        }
        
        try {
            DB::reconnect();
            $valid = DB::connection()->getDatabaseName() ? true : false;
        } catch (Exception $e) {
            return $e->getMessage();
        }

        return $valid;
    }

    private function testMail($mail)
    {
        $email = $mail['username'];
        $fromName = $mail['from']['name'];

        foreach ($mail as $key => $val) {
            Config::set("mail.{$key}", $val);
        }

        Config::set('mail.from.address', $email);
        Config::set('mail.from.name', $fromName);
        
        $data = [
            'text' => 'Test email',
        ];

        try {
            $response = $this->mailer->sendTo($email, $email, $fromName, 'Test email', 'contact', $data);

            return $response === true ? 'Sent' : $response;
        } catch (Exception $e) {
            return $e->getMessage();
        }
    }

    public function install()
    {
        if (!Utils::isNinjaProd() && !Utils::isDatabaseSetup()) {
            try {
                set_time_limit(60 * 5); // shouldn't take this long but just in case
                Artisan::call('migrate', array('--force' => true));
                if (Industry::count() == 0) {
                    Artisan::call('db:seed', array('--force' => true));
                }
                Artisan::call('optimize', array('--force' => true));
            } catch (Exception $e) {
                Response::make($e->getMessage(), 500);
            }
        }

        return Redirect::to('/');
    }

    public function update()
    {
        if (!Utils::isNinjaProd()) {
            try {
                set_time_limit(60 * 5);
                Artisan::call('optimize', array('--force' => true));
                Cache::flush();
                Session::flush();
                Artisan::call('migrate', array('--force' => true));
                foreach ([
                    'PaymentLibraries',
                    'Fonts',
                    'Banks',
                    'InvoiceStatus',
                    'Currencies',
                    'DateFormats',
                    'InvoiceDesigns',
                    'PaymentTerms',
                ] as $seeder) {
                    Artisan::call('db:seed', array('--force' => true, '--class' => "{$seeder}Seeder"));
                }
                Event::fire(new UserSettingsChanged());
                Session::flash('message', trans('texts.processed_updates'));
            } catch (Exception $e) {
                Response::make($e->getMessage(), 500);
            }
        }

        return Redirect::to('/');
    }

    public function emailBounced()
    {
        $messageId = Input::get('MessageID');
        $error = Input::get('Name') . ': ' . Input::get('Description');
        return $this->emailService->markBounced($messageId, $error) ? RESULT_SUCCESS : RESULT_FAILURE;
    }

    public function emailOpened()
    {
        $messageId = Input::get('MessageID');
        return $this->emailService->markOpened($messageId) ? RESULT_SUCCESS : RESULT_FAILURE;
        
        return RESULT_SUCCESS;
    }

    public function stats()
    {
        if (Input::get('password') != env('RESELLER_PASSWORD')) {
            sleep(3);
            return '';
        }

        if (Utils::getResllerType() == RESELLER_REVENUE_SHARE) {
            $data = DB::table('accounts')
                            ->leftJoin('payments', 'payments.account_id', '=', 'accounts.id')
                            ->leftJoin('clients', 'clients.id', '=', 'payments.client_id')
                            ->where('accounts.account_key', '=', NINJA_ACCOUNT_KEY)
                            ->where('payments.is_deleted', '=', false)
                            ->get([
                                'clients.public_id as client_id',
                                'payments.public_id as payment_id',
                                'payments.payment_date',
                                'payments.amount'
                            ]);
        } else {
            $data = DB::table('users')->count();
        }

        return json_encode($data);
    }
}