<?php

namespace App\Controllers\Api\Admin;

use App\Models\RewarderShopModel;
use App\Models\RewarderShopSubscriptionModel;
use App\Models\RewarderShopUserModel;
use App\Models\RewarderSubscriptionModel;
use CodeIgniter\HTTP\ResponseInterface;

class Shops extends BaseAdminApiController
{
    public function index(): ResponseInterface
    {
        if (!$this->isShopkeeper()) {
            if ($resp = $this->requirePermission('shops_list')) {
                return $resp;
            }
        }

        $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 ($this->isShopkeeper()) {
            $user = $this->user();
            if ($user) {
                $builder
                    ->join('rewarder_shop_users su', 'su.shop_id = sh.id', 'inner')
                    ->where('su.user_id', (int) $user->id)
                    ->groupBy('sh.id');
            }
        }

        $shops = $builder
            ->orderBy('sh.id', 'desc')
            ->get()
            ->getResult();

        foreach ($shops as $s) {
            $s->image_url = !empty($s->img_type)
                ? urlUpload('shops/' . $s->id . '.' . $s->img_type, true)
                : admin_assets('img/default-150x150.png');
            $s->status_label = (int) ($s->status ?? 0) ? 'Active' : 'Inactive';
        }

        return $this->ok($shops);
    }

    public function show(int $id): ResponseInterface
    {
        if (!$this->isShopkeeper()) {
            if ($resp = $this->requirePermission('shops_view')) {
                return $resp;
            }
        }

        $db = db_connect();

        $shopQ = $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);

        if ($this->isShopkeeper()) {
            $user = $this->user();
            if ($user) {
                $shopQ
                    ->join('rewarder_shop_users su', 'su.shop_id = sh.id', 'inner')
                    ->where('su.user_id', (int) $user->id);
            }
        }

        $shop = $shopQ->get()->getRow();
        if (!$shop) {
            return $this->fail('Not found', 404);
        }
        $shop->image_url = !empty($shop->img_type) ? urlUpload('shops/' . $shop->id . '.' . $shop->img_type, true) : null;
        $shop->status_label = (int) ($shop->status ?? 0) ? 'Active' : 'Inactive';

        $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;

        $dtFormat = (string) (setting('datetime_format') ?: 'd M, Y H:i:s');
        $subscriptionsOut = array_values(array_map(function ($ss) use ($dtFormat) {
            return $this->formatSubscription($ss, $dtFormat);
        }, $subscriptions));
        $currentOut = $currentSubscription ? $this->formatSubscription($currentSubscription, $dtFormat) : null;

        $ownerOut = null;
        if (!empty($owner) && !empty($owner->id)) {
            $contact = $owner->phone ?: $owner->email;
            $ownerOut = (object) [
                'id' => (int) $owner->id,
                'name' => (string) ($owner->name ?? ''),
                'phone' => (string) ($owner->phone ?? ''),
                'email' => (string) ($owner->email ?? ''),
                'display' => trim((string) ($owner->name ?? '')) . ' (' . (string) $contact . ')',
            ];
        }

        return $this->ok([
            'shop' => $shop,
            'owner' => $ownerOut,
            'subscriptions' => $subscriptionsOut,
            'current_subscription' => $currentOut,
        ]);
    }

    public function create(): ResponseInterface
    {
        if ($resp = $this->requirePermission('shops_add')) {
            return $resp;
        }

        $name = trim((string) $this->input('name', ''));
        if ($name === '') {
            return $this->fail('Validation failed', 422, ['name' => 'Name is required']);
        }

        $subscriptionId = (int) $this->input('subscription_id', 0);
        if ($subscriptionId < 1) {
            return $this->fail('Validation failed', 422, ['subscription_id' => 'Subscription is required']);
        }

        $slug = $this->makeUniqueSlug($name);

        $shopId = (new RewarderShopModel())->create([
            'name' => $name,
            'slug' => $slug,
            'phone' => (string) $this->input('phone', ''),
            'address' => (string) $this->input('address', ''),
            'city_id' => $this->input('city_id') ? (int) $this->input('city_id') : null,
            'category_id' => $this->input('category_id') ? (int) $this->input('category_id') : null,
            'status' => (int) $this->input('status', 1),
            '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'),
            ]);
        }

        $ownerUserId = (int) $this->input('owner_user_id', 0);
        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);

        $shop = (new RewarderShopModel())->getById($shopId);
        if ($shop) {
            $shop->image_url = !empty($shop->img_type) ? urlUpload('shops/' . $shop->id . '.' . $shop->img_type, true) : null;
        }

        return $this->ok($shop, [], 201);
    }

    public function update(int $id): ResponseInterface
    {
        if ($resp = $this->requirePermission('shops_edit')) {
            return $resp;
        }

        $shop = (new RewarderShopModel())->getById($id);
        if (!$shop) {
            return $this->fail('Not found', 404);
        }

        if ($this->isShopkeeper()) {
            $user = $this->user();
            if ($user) {
                $allowed = (new RewarderShopUserModel())
                    ->where(['shop_id' => (int) $id, 'user_id' => (int) $user->id])
                    ->first();
                if (!$allowed) {
                    return $this->fail('Not found', 404);
                }
            }
        }

        $name = trim((string) $this->input('name', ''));
        if ($name === '') {
            return $this->fail('Validation failed', 422, ['name' => 'Name is required']);
        }

        $subscriptionId = (int) $this->input('subscription_id', 0);
        if ($subscriptionId < 1) {
            return $this->fail('Validation failed', 422, ['subscription_id' => 'Subscription is required']);
        }

        $data = [
            'name' => $name,
            'phone' => (string) $this->input('phone', ''),
            'address' => (string) $this->input('address', ''),
            'city_id' => $this->input('city_id') ? (int) $this->input('city_id') : null,
            'category_id' => $this->input('category_id') ? (int) $this->input('category_id') : null,
            'status' => (int) $this->input('status', 1),
            'updated_at' => date('Y-m-d H:i:s'),
        ];

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

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

        (new RewarderShopModel())->update($id, $data);

        if (!$this->isShopkeeper()) {
            $ownerUserId = (int) $this->input('owner_user_id', 0);
            $shopUserModel = new RewarderShopUserModel();
            $existingOwner = $shopUserModel->where(['shop_id' => $id, 'role' => 'OWNER'])->first();
            if ($existingOwner) {
                if ($ownerUserId) {
                    $shopUserModel->update((int) $existingOwner->id, ['user_id' => $ownerUserId]);
                } else {
                    $shopUserModel->delete((int) $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);

        $shop = (new RewarderShopModel())->getById($id);
        if ($shop) {
            $shop->image_url = !empty($shop->img_type) ? urlUpload('shops/' . $shop->id . '.' . $shop->img_type, true) : null;
        }

        return $this->ok($shop);
    }

    public function delete(int $id): ResponseInterface
    {
        if ($resp = $this->requirePermission('shops_delete')) {
            return $resp;
        }

        if ($this->isShopkeeper()) {
            return $this->fail('Forbidden', 403);
        }

        (new RewarderShopUserModel())->where('shop_id', $id)->delete();
        (new RewarderShopSubscriptionModel())->where('shop_id', $id)->delete();
        (new RewarderShopModel())->delete($id);

        return $this->ok(true);
    }

    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) $this->input('subscription_id', 0);
        if ($subscriptionId < 1) {
            return;
        }
        $sub = (new RewarderSubscriptionModel())->getById($subscriptionId);
        if (!$sub) {
            return;
        }

        $startAt = trim((string) $this->input('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);

        $user = $this->user();
        $createdBy = $user ? (int) $user->id : 0;

        $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' => (string) ($this->input('subscription_status', 'ACTIVE') ?: 'ACTIVE'),
            'created_by' => $createdBy,
            'created_at' => date('Y-m-d H:i:s'),
        ];

        if ($existing) {
            $model->update((int) $existing->id, $payload);
            return;
        }

        $model->create($payload);
    }

    private function formatSubscription($row, string $dtFormat): object
    {
        $startFormatted = !empty($row->start_at) ? date($dtFormat, strtotime($row->start_at)) : '-';
        $endFormatted = !empty($row->end_at) ? date($dtFormat, strtotime($row->end_at)) : '-';

        $base = (float) ($row->base_price ?? 0);
        $tax = (float) ($row->tax_total ?? 0);
        $total = (float) ($row->total_amount ?? 0);

        return (object) [
            'id' => (int) ($row->id ?? 0),
            'shop_id' => isset($row->shop_id) ? (int) $row->shop_id : null,
            'subscription_id' => isset($row->subscription_id) ? (int) $row->subscription_id : null,
            'subscription_title' => (string) ($row->subscription_title ?? ''),
            'status' => (string) ($row->status ?? ''),
            'start_at' => $row->start_at ?? null,
            'end_at' => $row->end_at ?? null,
            'start_at_formatted' => $startFormatted,
            'end_at_formatted' => $endFormatted,
            'base_price' => $base,
            'tax_total' => $tax,
            'total_amount' => $total,
            'base_price_formatted' => $this->formatInr($base),
            'tax_total_formatted' => $this->formatInr($tax),
            'total_amount_formatted' => $this->formatInr($total),
            'amount_formatted' => 'Base: ' . $this->formatInr($base) . ', Tax: ' . $this->formatInr($tax) . ', Total: ' . $this->formatInr($total),
        ];
    }

    private function formatInr(float $amount): string
    {
        return '₹' . number_format($amount, 2);
    }
}
