<?php

namespace App\Controllers;

use App\Models\RewarderCityModel;
use App\Models\RewarderShopCategoryModel;
use App\Models\RewarderShopModel;
use App\Models\RewarderShopSubscriptionModel;
use App\Models\RewarderShopUserModel;
use App\Models\RewarderSubscriptionModel;
use App\Models\RoleModel;
use App\Models\UserModel;

class Shops extends AdminBaseController
{
    public $title = 'Shops';
    public $menu = 'rewarder';
    public $submenu = 'shops';

    public function index()
    {
        $this->permissionCheck('shops_list');
        $db = db_connect();
        $builder = $db->table('rewarder_shops sh')
            ->select('sh.*, sub.title as subscription_title, ss.start_at as subscription_start_at, ss.end_at as subscription_end_at, ss.status as subscription_status')
            ->join('(SELECT MAX(id) AS id, shop_id FROM rewarder_shop_subscriptions GROUP BY shop_id) last_ss', 'last_ss.shop_id = sh.id', 'left')
            ->join('rewarder_shop_subscriptions ss', 'ss.id = last_ss.id', 'left')
            ->join('rewarder_subscriptions sub', 'sub.id = ss.subscription_id', 'left');

        if (function_exists('is_role') && is_role('Shopkeeper')) {
            $builder
                ->join('rewarder_shop_users su', 'su.shop_id = sh.id', 'inner')
                ->where('su.user_id', (int) logged('id'))
                ->groupBy('sh.id');
        }

        $shops = $builder
            ->orderBy('sh.id', 'desc')
            ->get()
            ->getResult();
        return view('admin/shops/list', compact('shops'));
    }

    public function view($id)
    {
        $this->permissionCheck('shops_view');
        $db = db_connect();

        $shop = $db->table('rewarder_shops sh')
            ->select('sh.*, c.name as city_name, cat.name as category_name')
            ->join('rewarder_cities c', 'c.id = sh.city_id', 'left')
            ->join('rewarder_shop_categories cat', 'cat.id = sh.category_id', 'left')
            ->where('sh.id', (int) $id)
            ->get()
            ->getRow();

        if (!$shop) {
            return redirect()->to('shops')->with('notifyError', 'Shop not found');
        }

        if (empty($shop->qr_type)) {
            $known = ['png', 'jpg', 'jpeg', 'webp', 'gif'];
            foreach ($known as $ext) {
                $existing = FCPATH . 'uploads' . DIRECTORY_SEPARATOR . 'shops' . DIRECTORY_SEPARATOR . 'qr' . DIRECTORY_SEPARATOR . $shop->id . '.' . $ext;
                if (is_file($existing)) {
                    $shop->qr_type = $ext;
                    break;
                }
            }
        }

        if (empty($shop->qr_type)) {
            $shop->qr_type = $this->generateShopQr((int) $shop->id);
        }

        if (!empty($shop->qr_type) && $db->fieldExists('qr_type', 'rewarder_shops')) {
            (new RewarderShopModel())->update((int) $shop->id, [
                'qr_type' => $shop->qr_type,
                'updated_at' => date('Y-m-d H:i:s'),
            ]);
        }

        $owner = $db->table('rewarder_shop_users su')
            ->select('u.*')
            ->join('users u', 'u.id = su.user_id', 'left')
            ->where('su.shop_id', (int) $id)
            ->where('su.role', 'OWNER')
            ->get()
            ->getRow();

        $subscriptions = $db->table('rewarder_shop_subscriptions ss')
            ->select('ss.*, sub.title as subscription_title')
            ->join('rewarder_subscriptions sub', 'sub.id = ss.subscription_id', 'left')
            ->where('ss.shop_id', (int) $id)
            ->orderBy('ss.id', 'desc')
            ->get()
            ->getResult();

        $currentSubscription = $subscriptions[0] ?? null;

        return view('admin/shops/view', compact('shop', 'owner', 'subscriptions', 'currentSubscription'));
    }

    public function add()
    {
        $this->permissionCheck('shops_add');
        $shopkeepers = $this->getShopkeepers();
        $cities = (new RewarderCityModel())->activeOptionList();
        $categories = (new RewarderShopCategoryModel())->where('status', 1)->orderBy('name', 'asc')->findAll();
        $subscriptions = (new RewarderSubscriptionModel())->where('status', 1)->orderBy('title', 'asc')->findAll();
        return view('admin/shops/add', compact('shopkeepers', 'cities', 'categories', 'subscriptions'));
    }

    public function save()
    {
        $this->permissionCheck('shops_add');
        postAllowed();

        $name = post('name');
        $subscriptionId = (int) post('subscription_id');
        if ($subscriptionId < 1) {
            return redirect()->back()->withInput()->with('notifyError', 'Subscription is required');
        }
        $slug = $this->makeUniqueSlug($name);

        $shopId = (new RewarderShopModel())->create([
            'name' => $name,
            'slug' => $slug,
            'phone' => post('phone'),
            'address' => post('address'),
            'city_id' => post('city_id') ? (int) post('city_id') : null,
            'category_id' => post('category_id') ? (int) post('category_id') : null,
            'status' => (int) post('status'),
            'created_at' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s'),
        ]);

        $ext = uploadPublicImage('image', 'shops', (string) $shopId);
        if ($ext) {
            (new RewarderShopModel())->update($shopId, [
                'img_type' => $ext,
                'updated_at' => date('Y-m-d H:i:s'),
            ]);
        }

        $qrExt = $this->generateShopQr((int) $shopId);
        if ($qrExt && db_connect()->fieldExists('qr_type', 'rewarder_shops')) {
            (new RewarderShopModel())->update($shopId, [
                'qr_type' => $qrExt,
                'updated_at' => date('Y-m-d H:i:s'),
            ]);
        }

        $ownerUserId = (int) post('owner_user_id');
        if ($ownerUserId) {
            (new RewarderShopUserModel())->create([
                'shop_id' => $shopId,
                'user_id' => $ownerUserId,
                'role' => 'OWNER',
                'created_at' => date('Y-m-d H:i:s'),
            ]);
        }
        $this->syncShopSubscription((int) $shopId);

        return redirect()->to('shops')->with('notifySuccess', 'Shop created successfully');
    }

    public function createShopkeeperUser()
    {
        $this->permissionCheck('shops_add');
        postAllowed();

        $name = trim((string) post('name'));
        $phone = trim((string) post('phone'));
        $email = trim((string) post('email'));
        $username = trim((string) post('username'));
        $password = (string) post('password');
        $confirmPassword = (string) post('confirm_password');
        $countryId = (int) post('countryid') ?: 91;

        if ($name === '' || $phone === '' || $email === '' || $username === '' || $password === '' || $confirmPassword === '') {
            return $this->response->setJSON(['success' => false, 'message' => 'All fields are required'])->setStatusCode(400);
        }
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return $this->response->setJSON(['success' => false, 'message' => 'Invalid email'])->setStatusCode(400);
        }
        if (strlen($password) < 6) {
            return $this->response->setJSON(['success' => false, 'message' => 'Password must be at least 6 characters'])->setStatusCode(400);
        }
        if ($password !== $confirmPassword) {
            return $this->response->setJSON(['success' => false, 'message' => 'Password and confirm password must match'])->setStatusCode(400);
        }

        $userModel = new UserModel();
        if ($userModel->where('email', $email)->first()) {
            return $this->response->setJSON(['success' => false, 'message' => 'Email already exists'])->setStatusCode(400);
        }
        if ($userModel->where('username', $username)->first()) {
            return $this->response->setJSON(['success' => false, 'message' => 'Username already exists'])->setStatusCode(400);
        }

        $roleModel = new RoleModel();
        $role = $roleModel->where('title', 'Shopkeeper')->first();
        if (!$role) {
            $roleId = $roleModel->create(['title' => 'Shopkeeper']);
            $role = (object) ['id' => $roleId];
        }

        $now = date('Y-m-d H:i:s');
        $id = $userModel->create([
            'role' => (int) $role->id,
            'name' => $name,
            'username' => $username,
            'email' => $email,
            'phone' => $phone,
            'countryid' => $countryId,
            'address' => '',
            'status' => 1,
            'password' => hash('sha256', $password),
            'created_at' => $now,
            'updated_at' => $now,
        ]);

        if (!$id) {
            return $this->response->setJSON(['success' => false, 'message' => 'Unable to create user'])->setStatusCode(500);
        }

        $ext = uploadPublicImage('profile_image', 'users', (string) $id);
        if ($ext) {
            $userModel->update($id, ['img_type' => $ext]);
        } else {
            if (!is_dir(FCPATH . 'uploads/users')) {
                mkdir(FCPATH . 'uploads/users', 0777, true);
            }
            copy(FCPATH . 'uploads/users/default.png', 'uploads/users/' . $id . '.png');
            $userModel->update($id, ['img_type' => 'png']);
        }

        model('App\Models\ActivityLogModel')->add('New User $' . $id . ' Created by User:' . logged('name'), logged('id'));

        return $this->response->setJSON([
            'success' => true,
            'user' => [
                'id' => (int) $id,
                'name' => $name,
                'username' => $username,
                'email' => $email,
            ],
        ]);
    }

    public function edit($id)
    {
        $this->permissionCheck('shops_edit');
        $shop = (new RewarderShopModel())->getById($id);
        $shopkeepers = $this->getShopkeepers();
        $cities = (new RewarderCityModel())->activeOptionList();
        $categories = (new RewarderShopCategoryModel())->where('status', 1)->orderBy('name', 'asc')->findAll();
        $subscriptions = (new RewarderSubscriptionModel())->where('status', 1)->orderBy('title', 'asc')->findAll();
        $owner = (new RewarderShopUserModel())->where(['shop_id' => $id, 'role' => 'OWNER'])->first();
        $ownerUserId = $owner ? (int) $owner->user_id : 0;
        $shopSubscription = (new RewarderShopSubscriptionModel())->where('shop_id', (int) $id)->orderBy('id', 'desc')->first();
        return view('admin/shops/edit', compact('shop', 'shopkeepers', 'ownerUserId', 'cities', 'categories', 'subscriptions', 'shopSubscription'));
    }

    public function update($id)
    {
        $this->permissionCheck('shops_edit');
        postAllowed();

        $shopModel = new RewarderShopModel();
        $shop = $shopModel->getById($id);
        if (!$shop) {
            return redirect()->to('shops')->with('notifyError', 'Shop not found');
        }

        $name = post('name');
        $subscriptionId = (int) post('subscription_id');
        if ($subscriptionId < 1) {
            return redirect()->back()->withInput()->with('notifyError', 'Subscription is required');
        }
        $data = [
            'name' => $name,
            'phone' => post('phone'),
            'address' => post('address'),
            'city_id' => post('city_id') ? (int) post('city_id') : null,
            'category_id' => post('category_id') ? (int) post('category_id') : null,
            'status' => (int) post('status'),
            'updated_at' => date('Y-m-d H:i:s'),
        ];

        $ext = uploadPublicImage('image', 'shops', (string) $id);
        if ($ext) {
            $data['img_type'] = $ext;
        }

        if (post('regenerate_slug') == 1) {
            $data['slug'] = $this->makeUniqueSlug($name, (int) $id);
        }

        $qrType = $shop->qr_type ?? null;
        if (empty($qrType)) {
            $known = ['png', 'jpg', 'jpeg', 'webp', 'gif'];
            foreach ($known as $ext) {
                $existing = FCPATH . 'uploads' . DIRECTORY_SEPARATOR . 'shops' . DIRECTORY_SEPARATOR . 'qr' . DIRECTORY_SEPARATOR . $shop->id . '.' . $ext;
                if (is_file($existing)) {
                    $qrType = $ext;
                    break;
                }
            }
        }

        if (empty($qrType)) {
            $qrType = $this->generateShopQr((int) $shop->id);
        }

        if (!empty($qrType) && db_connect()->fieldExists('qr_type', 'rewarder_shops')) {
            $data['qr_type'] = $qrType;
        }

        $shopModel->update($id, $data);

        $ownerUserId = (int) post('owner_user_id');
        $shopUserModel = new RewarderShopUserModel();
        $existingOwner = $shopUserModel->where(['shop_id' => $id, 'role' => 'OWNER'])->first();
        if ($existingOwner) {
            if ($ownerUserId) {
                $shopUserModel->update($existingOwner->id, ['user_id' => $ownerUserId]);
            } else {
                $shopUserModel->delete($existingOwner->id);
            }
        } else {
            if ($ownerUserId) {
                $shopUserModel->create([
                    'shop_id' => $id,
                    'user_id' => $ownerUserId,
                    'role' => 'OWNER',
                    'created_at' => date('Y-m-d H:i:s'),
                ]);
            }
        }
        $this->syncShopSubscription((int) $id);

        return redirect()->to('shops')->with('notifySuccess', 'Shop updated successfully');
    }

    public function delete($id)
    {
        $this->permissionCheck('shops_delete');
        (new RewarderShopUserModel())->where('shop_id', $id)->delete();
        (new RewarderShopSubscriptionModel())->where('shop_id', $id)->delete();
        (new RewarderShopModel())->delete($id);
        return redirect()->to('shops')->with('notifySuccess', 'Shop deleted successfully');
    }

    private function getShopkeepers()
    {
        $role = (new RoleModel())->where('title', 'Shopkeeper')->first();
        if (!$role) {
            return [];
        }
        return (new UserModel())->where('role', $role->id)->orderBy('name', 'asc')->findAll();
    }

    private function makeUniqueSlug(string $name, int $ignoreId = 0): string
    {
        $base = strtolower(trim(preg_replace('/[^a-zA-Z0-9]+/', '-', $name), '-'));
        $base = $base ?: 'shop';
        $slug = $base;
        $model = new RewarderShopModel();

        $i = 1;
        while (true) {
            $builder = $model->where('slug', $slug);
            if ($ignoreId) {
                $builder = $builder->where('id !=', $ignoreId);
            }
            if (!$builder->first()) {
                return $slug;
            }
            $i++;
            $slug = $base . '-' . $i;
        }
    }

    private function syncShopSubscription(int $shopId): void
    {
        $subscriptionId = (int) post('subscription_id');
        if ($subscriptionId < 1) {
            return;
        }
        $sub = (new RewarderSubscriptionModel())->getById($subscriptionId);
        if (!$sub) {
            return;
        }

        $startAt = trim((string) post('subscription_start_at'));
        if ($startAt === '') {
            $startAt = date('Y-m-d H:i:s');
        }
        $startDt = new \DateTime($startAt);
        $endDt = (clone $startDt)->add(new \DateInterval('P' . (int) ($sub->duration_months ?? 0) . 'M'));
        $endAt = $endDt->format('Y-m-d H:i:s');

        $taxInclusive = (int) setting('subscription_tax_inclusive') ? 1 : 0;
        $taxGroupId = (int) setting('subscription_tax_group_id') ?: null;
        $basePrice = (float) ($sub->price ?? 0);
        $taxTotal = 0.0;
        if ($taxGroupId) {
            $db = db_connect();
            $taxes = $db->table('rewarder_tax_group_items gi')
                ->select('t.*')
                ->join('rewarder_taxes t', 't.id = gi.tax_id', 'left')
                ->where('gi.group_id', $taxGroupId)
                ->where('t.status', 1)
                ->get()->getResult();
            foreach ($taxes as $t) {
                if (($t->rate_type ?? '') === 'PERCENT') {
                    $taxTotal += ($basePrice * ((float) ($t->rate ?? 0)) / 100.0);
                } else {
                    $taxTotal += (float) ($t->rate ?? 0);
                }
            }
        }
        $totalAmount = $taxInclusive ? $basePrice : ($basePrice + $taxTotal);

        $model = new RewarderShopSubscriptionModel();
        $existing = $model->where('shop_id', $shopId)->orderBy('id', 'desc')->first();
        $payload = [
            'shop_id' => $shopId,
            'subscription_id' => $subscriptionId,
            'base_price' => $basePrice,
            'tax_group_id' => $taxGroupId,
            'tax_inclusive' => $taxInclusive,
            'tax_total' => $taxTotal,
            'total_amount' => $totalAmount,
            'start_at' => $startAt,
            'end_at' => $endAt,
            'status' => post('subscription_status') ?: 'ACTIVE',
            'created_by' => function_exists('logged') ? (int) logged('id') : 0,
            'created_at' => date('Y-m-d H:i:s'),
        ];
        if ($existing) {
            $model->update((int) $existing->id, $payload);
            return;
        }
        $model->create($payload);
    }

    private function generateShopQr(int $shopId): ?string
    {
        $redirectUrl = url('shop/' . $shopId);
        $qrUrl = 'https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=' . rawurlencode($redirectUrl);
        $binary = $this->fetchRemoteBinary($qrUrl);
        if (!$binary) {
            return null;
        }

        $dir = FCPATH . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'shops' . DIRECTORY_SEPARATOR . 'qr';
        if (!is_dir($dir)) {
            if (!@mkdir($dir, 0777, true) && !is_dir($dir)) {
                return null;
            }
        }

        $filePath = $dir . DIRECTORY_SEPARATOR . $shopId . '.png';
        $bytes = @file_put_contents($filePath, $binary);
        if (!$bytes) {
            return null;
        }

        return 'png';
    }

    private function fetchRemoteBinary(string $url): ?string
    {
        if (function_exists('curl_init')) {
            $ch = curl_init($url);
            if (!$ch) {
                return null;
            }
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
            curl_setopt($ch, CURLOPT_TIMEOUT, 10);
            $body = curl_exec($ch);
            $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            if ($body === false || $httpCode < 200 || $httpCode >= 300) {
                return null;
            }
            return is_string($body) ? $body : null;
        }

        $ctx = stream_context_create([
            'http' => [
                'timeout' => 10,
                'follow_location' => 1,
            ],
        ]);
        $body = @file_get_contents($url, false, $ctx);
        return $body !== false ? $body : null;
    }
}
