<?php

namespace Server\Controllers;

use Server\Library\Controllers\AuthController;

use Server\Database\Models\User;
use Server\Database\Models\Trade;
use Server\Database\Models\Deposit;
use Server\Database\Models\RefdUser;
use Server\Database\Models\Withdrawal;

use Server\Library\Services\Sender; 
use Server\Library\Services\Logger;
use Server\Library\Services\Renderer;
use Server\Library\Services\Validator;

use Server\Controllers\Traits\AuthTrait;
use Server\Controllers\Filters\ApiFilter;
use Server\Library\Controllers\SolidController; 
use Server\Controllers\Validators\UsersValidator;

class UsersController extends SolidController
{
    use AuthTrait;

    public function __construct() 
    {
        $this->model = new User;
        $this->sender = new Sender;
        $this->logger = new Logger;
        $this->filter = new ApiFilter;
        $this->renderer = new Renderer;
        $this->validator = new Validator;
        $this->validator = new UsersValidator(new User);

        $this->authKey = 'user';
        $this->searchBy = 'first_name';
    }

    public function relationships($row)
    {
        return User::relationships($row);
    }

    // public function updateRules($body)
    // {
    //     $country = $body['country'] ?? '';
    //     $street_address = $body['street_address'] ?? '';

    //     return [
    //         'country' => [$country, 'required'],
    //         'address' => [$street_address, 'required'],
    //     ];
    // }

    // public function updateBody($body, $row)
    // {
    //     return $this->filter($body, ['country', 'state', 'city', 'post_code', 'street_address', 'mobile_number']);
    // }




    // public function getListModel()
    // {
    //     $this->model = new RefdUser;
    //     return $this->model->latest();
    // }




    public function copyTrader($request, $response)
    {
        $body = $request->getParsedBody();

        $user_id = $body['user_id'] ?? '';
        $trader_id = $body['trader_id'] ?? '';

        $rules = [
            'user id' => [$user_id, 'required'],
            'trader id' => [$trader_id, 'required']
        ];

        $this->validator->validate($rules);

        $errors = $this->validator->errors()->all();

        if ($errors) {
            $this->data['errors'] = $errors;
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $user = $this->model->where('id', $user_id)->first();
        $user->traders()->toggle($trader_id);
        $user = $this->relationships($user);

        $this->data['data'] = $user;
        $response->getBody()->write(json_encode($this->data));
        return $response->withHeader('Content-Type', 'application/json');
    }

    public function leaderboard($request, $response)
    {
        $this->data['data'] = RefdUser::orderBy('trading_balance', "DESC")->limit(20)->get();
        $response->getBody()->write(json_encode($this->data));
        return $response->withHeader('Content-Type', 'application/json');
    }



    public function updateMessage($request, $response)
    {
        $body = $request->getParsedBody();
        $user_id = $body['id'] ?? '';

        $rules = ['user id' => [$user_id, 'required']];

        $this->validator->validate($rules);
        $errors = $this->validator->errors()->all();

        if ($errors) {
            $this->data['errors'] = $errors;
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $row = User::where('id', $user_id)->first();

        if (!$row) {
            $this->data['errors'] = ['not found'];
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $row->update($body);

        $user = $this->model->where('id', $user_id)->first();
        $user = $this->relationships($user);

        $this->data['data'] = $user;
        $response->getBody()->write(json_encode($this->data));
        return $response->withHeader('Content-Type', 'application/json');
    }

    public function sendPush($request, $response)
    {
        $body = $request->getParsedBody();
        $subject = $body['subject'] ?? "";
        $content = $body['body'] ?? "";
        $user_id = $body['user_id'] ?? "";

        $rules = [
            'subject' => [$subject, 'required'],
            'user_id' => [$user_id, 'required'],
            'body' => [$content, 'required'],
        ];

        $this->validator->validate($rules);
        $errors = $this->validator->errors()->all();

        if ($errors) {
            $this->data['errors'] = $errors;
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }


        $user = User::where('id', $user_id)->first();

        if (!$user) {
            $this->data['errors'] = ['not found'];
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $sent = $this->sender->sendPush([$user->push_subscription], $content, $subject);

        if ($sent) {
            $this->data['message'] = "Sent";

            $response->getBody()->write(json_encode($this->data));

            return $response->withHeader('Content-Type', 'application/json');
        }

        $this->data['errors'] = ["Failed To Send"];

        $response->getBody()->write(json_encode($this->data));

        return $response->withHeader('Content-Type', 'application/json');
    }

    public function sendEmail($request, $response)
    {
        $body = $request->getParsedBody();
        $subject = $body['subject'] ?? "";
        $content = $body['body'] ?? "";
        $user_id = $body['user_id'] ?? "";

        $rules = [
            'subject' => [$subject, 'required'],
            'user_id' => [$user_id, 'required'],
            'body' => [$content, 'required'],
        ];

        $this->validator->validate($rules);
        $errors = $this->validator->errors()->all();

        if ($errors) {
            $this->data['errors'] = $errors;
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }


        $user = User::where('id', $user_id)->first();

        if (!$user) {
            $this->data['errors'] = ['not found'];
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $content = nl2br($content);

        $content = $this->renderer->render("email.html", ['body' => $content, 'title' => $subject]);

        $sent = $this->sender->sendEmail([$user->email], $content, $subject);

        if ($sent) {
            $this->data['message'] = "Sent";

            $response->getBody()->write(json_encode($this->data));

            return $response->withHeader('Content-Type', 'application/json');
        }

        $this->data['errors'] = ["Failed To Send"];

        $response->getBody()->write(json_encode($this->data));

        return $response->withHeader('Content-Type', 'application/json');
    }

 
    public function createDeposit($request, $response)
    {
        $body = $request->getParsedBody();

        $user_id = $body['user_id'] ?? '';
        $for = $body['for'] ?? '';
        $amount = $body['amount'] ?? '';

        $rules =  [
            'user_id' => [$user_id, 'required'],
            'for' => [$for, 'required'],
            'amount' => [$amount, 'required|number'],
        ];

        $this->validator->validate($rules);
        $errors = $this->validator->errors()->all();

        if ($errors) {
            $this->data['errors'] = $errors;
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $body = $this->filter($body, ['user_id', 'crypto', 'for', 'crypto_amount', 'amount', 'link', 'address', 'payment_method', 'status']);
        Deposit::create($body);

        $user = $this->model->where('id', $user_id)->first();
        $user = $this->relationships($user);
        $this->data['data'] = $user;
        $response->getBody()->write(json_encode($this->data));
        return $response->withHeader('Content-Type', 'application/json');
    }

    public function updateDeposit($request, $response)
    {
        $body = $request->getParsedBody();
        $id = $body['id'] ?? '';
        $user_id = $body['user_id'] ?? '';
        $status = $body['status'] ?? '';

        $rules = [
            'id' => [$id, 'required'],
            'user_id' => [$user_id, 'required'],
            'status' => [$status, 'required'],
        ];

        $this->validator->validate($rules);
        $errors = $this->validator->errors()->all();

        if ($errors) {
            $this->data['errors'] = $errors;
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $row = Deposit::where('id', $id)->where('user_id', $user_id)->first();

        if (!$row) {
            $this->data['errors'] = ['not found'];
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $row->update($body);

        $user = $this->model->where('id', $user_id)->first();
        $user = $this->relationships($user);

        $this->data['data'] = $user;
        $response->getBody()->write(json_encode($this->data));
        return $response->withHeader('Content-Type', 'application/json');
    }

    public function deleteDeposit($request, $response)
    {
        $body = $request->getParsedBody();
        $id = $body['id'] ?? '';
        $user_id = $body['user_id'] ?? '';

        $rules = [
            'id' => [$id, 'required'],
            'user_id' => [$user_id, 'required'],
        ];

        $this->validator->validate($rules);
        $errors = $this->validator->errors()->all();
        if ($errors) {
            $this->data['errors'] = $errors;
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $row = Deposit::where('id', $id)->where('user_id', $user_id)->first();
        if (!$row) {
            $this->data['errors'] = ['not found'];
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }
        $row->delete();

        $user = $this->model->where('id', $user_id)->first();
        $user = $this->relationships($user);
        $this->data['data'] = $user;
        $response->getBody()->write(json_encode($this->data));
        return $response->withHeader('Content-Type', 'application/json');
    }

    public function createTrade($request, $response)
    {
        $body = $request->getParsedBody();
        $user_id = $body['user_id'] ?? '';
        $trader_id = $body['trader_id'] ?? '';
        $symbol = $body['symbol'] ?? '';
        $type = $body['type'] ?? '';
        $amount = $body['amount'] ?? '';
        $opening_price = $body['opening_price'] ?? '';


        $rules =  [
            'user_id' => [$user_id, 'required'],
            'symbol' => [$symbol, 'required'],
            'type' => [$type, 'required'],
            'amount' => [$amount, 'required|number'],
            'opening price' => [$opening_price, 'required|number'],
        ];

        $this->validator->validate($rules);
        $errors = $this->validator->errors()->all();

        if ($errors) {
            $this->data['errors'] = $errors;
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $body = $this->filter($body,  ['user_id', 'trader_id', 'symbol', 'type', 'amount', 'opening_price', 'stop_loss', 'take_profit','market','time','timestamp']);
        Trade::create($body);

        $user = $this->model->where('id', $user_id)->first();
        $user = $this->relationships($user);
        $this->data['data'] = $user;
        $response->getBody()->write(json_encode($this->data));
        return $response->withHeader('Content-Type', 'application/json');
    }

    public function updateTrade($request, $response)
    {
        $body = $request->getParsedBody();
        $user_id = $body['user_id'] ?? '';
        $id = $body['id'] ?? '';

        $rules = [
            'user_id' => [$user_id, 'required'],
            'id' => [$id, 'required'],
        ];

        $this->validator->validate($rules);
        $errors = $this->validator->errors()->all();

        if ($errors) {
            $this->data['errors'] = $errors;
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $row = Trade::where('id', $id)->where('user_id', $user_id)->first();

        if (!$row) {
            $this->data['errors'] = ['not found'];
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $row->update($body);

        $user = $this->model->where('id', $user_id)->first();
        $user = $this->relationships($user);

        $this->data['data'] = $user;
        $response->getBody()->write(json_encode($this->data));
        return $response->withHeader('Content-Type', 'application/json');
    }

    public function updateTradeDate($request, $response)
    {
        $body = $request->getParsedBody();
        $user_id = $body['user_id'] ?? '';
        $id = $body['id'] ?? '';

        $rules = [
            'user_id' => [$user_id, 'required'],
            'id' => [$id, 'required'],
        ];

        $this->validator->validate($rules);
        $errors = $this->validator->errors()->all();

        if ($errors) {
            $this->data['errors'] = $errors;
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $row = Trade::where('id', $id)->where('user_id', $user_id)->first();

        if (!$row) {
            $this->data['errors'] = ['not found'];
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $row->update($body);

        $user = $this->model->where('id', $user_id)->first();
        $user = $this->relationships($user);

        $this->data['data'] = $user;
        $response->getBody()->write(json_encode($this->data));
        return $response->withHeader('Content-Type', 'application/json');
    }

    public function createWithdrawal($request, $response)
    {
        $body = $request->getParsedBody();

        $from = $body['from'] ?? '';
        $user_id = $body['user_id'] ?? '';
        $payment_method = $body['payment_method'];
        $amount_in_crypto = $body['amount_in_crypto'] ?? $body['amount'];

        $rules =  [
            'from' => [$from, 'required'],
            'user_id' => [$user_id, 'required'],
            'payment_method' => [$payment_method, 'required'],
        ];

        $this->validator->validate($rules);

        $errors = $this->validator->errors()->all();

        if ($errors) {
            $this->data['errors'] = $errors;
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        $user = $this->model->where('id', $user_id)->first();

        if ($body['from'] == 1) {
            // Trading
            $trading_balance = $user->trading_balance;
            if ($amount_in_crypto > $trading_balance) {
                $this->data['errors'] = ['insufficent funds'];
                $response->getBody()->write(json_encode($this->data));
                return $response->withHeader('Content-Type', 'application/json');
            }
        }

        if ($amount_in_crypto == 0) {
            $this->data['errors'] = ['CANNOT WITHDRAW 0'];
            $response->getBody()->write(json_encode($this->data));
            return $response->withHeader('Content-Type', 'application/json');
        }

        if ($body['from'] == 2) {
            // Bitcoin Mining
            if ($amount_in_crypto > $user->mining_balance_bitcoin) {
                $this->data['errors'] = ['insufficent funds'];
                $response->getBody()->write(json_encode($this->data));
                return $response->withHeader('Content-Type', 'application/json');
            }
        }

        if ($body['from'] == 3) {
            // Ethereum Mining
            if ($amount_in_crypto > $user->mining_balance_ethereum) {
                $this->data['errors'] = ['insufficent funds'];
                $response->getBody()->write(json_encode($this->data));
                return $response->withHeader('Content-Type', 'application/json');
            }
        }

        if ($body['from'] == 4) {
            // Dash Mining
            if ($amount_in_crypto > $user->mining_balance_dash) {
                $this->data['errors'] = ['insufficent funds'];
                $response->getBody()->write(json_encode($this->data));
                return $response->withHeader('Content-Type', 'application/json');
            }
        }

        if ($body['from'] == 5) {
            // Litecoin Mining
            if ($amount_in_crypto > $user->mining_balance_litecoin) {
                $this->data['errors'] = ['insufficent funds'];
                $response->getBody()->write(json_encode($this->data));
                return $response->withHeader('Content-Type', 'application/json');
            }
        }

        if ($body['from'] == 6) {
            // Zcash Mining
            if ($amount_in_crypto > $user->mining_balance_zcash) {
                $this->data['errors'] = ['insufficent funds'];
                $response->getBody()->write(json_encode($this->data));
                return $response->withHeader('Content-Type', 'application/json');
            }
        }

        if ($body['from'] == 7) {
            // Monero Mining
            if ($amount_in_crypto > $user->mining_balance_monero) {
                $this->data['errors'] = ['insufficent funds'];
                $response->getBody()->write(json_encode($this->data));
                return $response->withHeader('Content-Type', 'application/json');
            }
        }

        $body = $this->filter($body, ['user_id', 'from', 'amount', 'paypal_email', 'bank_name', 'account_number', 'routing_number', 'currency', 'amount_in_crypto', 'wallet_address', 'account_name']);

        Withdrawal::create($body);

        $user = $this->model->where('id', $user_id)->first();
        $user = $this->relationships($user);

        $this->data['data'] = $user;
        $response->getBody()->write(json_encode($this->data));
        return $response->withHeader('Content-Type', 'application/json');
    }


}