<?php

namespace App\Http\Controllers;

use App\Models\PartnerClickRef;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Yajny\Member\Models\Click;
use Yajny\Models\Store;

class PartnerController extends Controller
{
    const MAX_REPORT_RANGE_DAYS = 92;
    const MAX_PAGE_SIZE = 500;

    /**
     * POST /partner/v1/links
     * Create a tracking link. The click id is the numeric SubTag reported back by networks.
     * Idempotent per (partner, external_ref): repeating a request returns the existing link.
     */
    public function createLink(Request $request)
    {
        $partner = $request->attributes->get('partner');

        $this->validate($request, [
            'store_id' => 'required_without:store_url|integer',
            'store_url' => 'required_without:store_id|url',
            'external_ref' => 'nullable|string|max:191',
            'custom_link' => 'nullable|url',
        ]);

        $externalRef = $request->input('external_ref');

        if ($externalRef) {
            $existing = PartnerClickRef::where('partner_id', $partner->id)
                ->where('external_ref', $externalRef)
                ->first();
            if ($existing) {
                $click = Click::withoutGlobalScopes()->find($existing->click_id);
                return response()->json([
                    'subtag' => $existing->click_id,
                    'external_ref' => $externalRef,
                    'tracking_url' => $click ? str_replace('CBCLKID', $click->id, $click->redirect_link) : null,
                    'idempotent_replay' => true,
                ]);
            }
        }

        $store = $this->resolveStore($request);
        if (!$store) {
            return response()->json(['error' => 'NO_STORE', 'message' => 'Store not found for the given id/url'], 422);
        }

        $result = $this->mintClick($store, (int) $partner->user_id, $request->input('custom_link'));

        if ($externalRef) {
            PartnerClickRef::create([
                'partner_id' => $partner->id,
                'click_id' => $result['click_id'],
                'external_ref' => $externalRef,
            ]);
        }

        return response()->json([
            'subtag' => $result['click_id'],
            'external_ref' => $externalRef,
            'tracking_url' => $result['url']['web'],
            'app_tracking_url' => $result['url']['app'],
            'store' => [
                'id' => $store->id,
                'name' => $store->name,
                'slug' => $store->slug,
                'cashback_enabled' => (bool) $store->cb_status,
            ],
        ], 201);
    }

    /**
     * GET /partner/v1/links/{externalRef}
     */
    public function lookupLink(Request $request, $externalRef)
    {
        $partner = $request->attributes->get('partner');

        $ref = PartnerClickRef::where('partner_id', $partner->id)
            ->where('external_ref', $externalRef)
            ->first();

        if (!$ref) {
            return response()->json(['error' => 'NOT_FOUND'], 404);
        }

        $click = Click::withoutGlobalScopes()->find($ref->click_id);

        return response()->json([
            'subtag' => $ref->click_id,
            'external_ref' => $ref->external_ref,
            'store_id' => $click ? $click->store_id : null,
            'created_at' => $ref->created_at ? (string) $ref->created_at : null,
        ]);
    }

    /**
     * GET /partner/v1/reports/performance?from=Y-m-d&to=Y-m-d[&store_id=][&subtag=][&cursor=][&per_page=]
     * Aggregated per subtag; no PII (no ip / referrer / member data). Cursor-paged (descending subtag).
     */
    public function performance(Request $request)
    {
        $partner = $request->attributes->get('partner');

        $this->validate($request, [
            'from' => 'required|date_format:Y-m-d',
            'to' => 'required|date_format:Y-m-d|after_or_equal:from',
            'store_id' => 'nullable|integer',
            'subtag' => 'nullable|integer',
            'cursor' => 'nullable|integer',
            'per_page' => 'nullable|integer|min:1|max:' . self::MAX_PAGE_SIZE,
        ]);

        $from = $request->input('from');
        $to = $request->input('to');
        if ((strtotime($to) - strtotime($from)) > self::MAX_REPORT_RANGE_DAYS * 86400) {
            return response()->json(['error' => 'RANGE_TOO_WIDE', 'max_days' => self::MAX_REPORT_RANGE_DAYS], 422);
        }

        $perPage = (int) $request->input('per_page', 100);

        $query = DB::table('clicks')
            ->leftJoin('partner_click_refs', 'partner_click_refs.click_id', '=', 'clicks.id')
            ->leftJoin('sales', 'sales.click_id', '=', 'clicks.id')
            ->where('clicks.user_id', $partner->user_id)
            ->whereBetween('clicks.click_time', [$from . ' 00:00:00', $to . ' 23:59:59'])
            ->groupBy('clicks.id', 'clicks.click_time', 'clicks.store_id', 'partner_click_refs.external_ref')
            ->orderBy('clicks.id', 'desc')
            ->select([
                'clicks.id as subtag',
                'clicks.click_time',
                'clicks.store_id',
                'partner_click_refs.external_ref',
                DB::raw('COUNT(sales.id) as sale_count'),
                DB::raw('COALESCE(SUM(sales.order_amount), 0) as order_amount_total'),
                DB::raw('COALESCE(SUM(sales.comission), 0) as commission_total'),
                DB::raw("GROUP_CONCAT(DISTINCT sales.status) as sale_statuses"),
            ]);

        if ($request->filled('store_id')) {
            $query->where('clicks.store_id', (int) $request->input('store_id'));
        }
        if ($request->filled('subtag')) {
            $query->where('clicks.id', (int) $request->input('subtag'));
        }
        if ($request->filled('cursor')) {
            $query->where('clicks.id', '<', (int) $request->input('cursor'));
        }

        $rows = $query->limit($perPage)->get();

        return response()->json([
            'from' => $from,
            'to' => $to,
            'count' => count($rows),
            'next_cursor' => count($rows) === $perPage ? $rows[count($rows) - 1]->subtag : null,
            'data' => $rows,
        ]);
    }

    /**
     * Resolve a store by id, or by url against the stores.domain_name regexp (bound, not interpolated).
     *
     * @return \Yajny\Models\Store|null
     */
    private function resolveStore(Request $request)
    {
        if ($request->filled('store_id')) {
            return Store::withoutGlobalScopes()->find((int) $request->input('store_id'));
        }
        return Store::withoutGlobalScopes()
            ->whereRaw('? REGEXP domain_name', [$request->input('store_url')])
            ->first();
    }

    /**
     * Mint a click for a service partner. Mirrors the 'store' path of Click::outClick()
     * without its Session / member-specific branches (Lumen has no session binding).
     *
     * @param \Yajny\Models\Store $store
     * @param int $userId
     * @param string|null $customLink
     * @return array
     */
    private function mintClick(Store $store, $userId, $customLink = null)
    {
        $redirectUrl = $customLink ?: $store->homepage;

        $dlUrl = ($store->dl_url_build && $store->cb_status) ? $store->dl_url_build : $redirectUrl;
        if ($dlUrl != $redirectUrl && strpos($redirectUrl, '?')
            && strpos($dlUrl, '?') && strpos($dlUrl, '#URL')) {
            $dlUrl = str_replace('?', '&', $dlUrl);
        }
        $dlUrl = str_replace(['#URL', '#EURL'], [$redirectUrl, urlencode($redirectUrl)], $dlUrl);
        $dlUrl = Click::str_replace_nth_skip('?', '&', $dlUrl, 1);

        $click = new Click;
        $click->store_id = $store->id;
        $click->user_id = $userId;
        $click->cashback_enabled = $store->cb_status;
        $click->cashback_percent = $store->cashback_percent;
        $click->ip_address = request()->ip();
        $click->source_type = 'partner';
        $click->source_id = $store->id;
        $click->cb_deal_type = $store->cb_deal_type;
        $click->cb_deal_value = $store->cb_deal_value;
        $click->network_id = $store->network_id;
        $click->redirect_link = $dlUrl;
        $click->original_link = $redirectUrl;
        $click->platform = 'api';
        $click->save();

        $store->increment('clicks');

        return [
            'url' => ['web' => str_replace('CBCLKID', $click->id, $dlUrl), 'app' => null],
            'click_id' => $click->id,
        ];
    }
}
