<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Http;
use App\Mail\DailyJewelryEmail;
use App\Models\EmailLog;
use App\Models\FeaturedProduct;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;

class EmailController extends Controller
{
    private $baseUrl;

    private const ADMIN_TO_EMAIL = 'customerservice@brillianttouchllc.com';
    private const ADMIN_TO_NAME  = 'BrilliantTouch';

    private const ADMIN_BCC = [
        'anand@braintreeproducts.com',
        'mitjain@gmail.com',
        'rachna@triplekeywholesale.com',
    ];

    private const TEST_RECIPIENTS = [
        ['email' => 'pinky@braintreeproducts.com',       'name' => 'pinky'],

    ];

    public function __construct()
    {
        $this->baseUrl = env('SHOPIFY_STORE_URL');
    }

    // ════════════════════════════════════════════════════════════════════════
    // TEST EMAIL — sends individually to each TEST_RECIPIENT
    // so every person gets their own copy in their inbox (not BCC)
    // ════════════════════════════════════════════════════════════════════════
    public function sendTestEmail()
    {
        $products = $this->getJewelryProducts();
        $tagspr   = ['tag' => 'salesperson'];

        $successList = [];
        $failList    = [];

        foreach (self::TEST_RECIPIENTS as $recipient) {

            try {
                // Send individually to each recipient as "To"
                // so it lands in inbox — not spam/BCC
                Mail::to($recipient['email'], $recipient['name'])
                    ->send(new DailyJewelryEmail(
                        $products['inexpensive'],
                        $products['expensive'],
                        $tagspr
                    ));

                $successList[] = $recipient['email'];

                Log::info('Test email sent', ['to' => $recipient['email']]);

            } catch (\Throwable $e) {

                $failList[] = $recipient['email'];

                Log::error('Test Email Failed', [
                    'to'      => $recipient['email'],
                    'message' => $e->getMessage(),
                    'file'    => $e->getFile(),
                    'line'    => $e->getLine(),
                    'trace'   => $e->getTraceAsString(),
                ]);
            }
        }

        return response()->json([
            'message'      => count($failList) === 0
                                ? 'All test emails sent successfully!'
                                : 'Some test emails failed!',
            'sent_to'      => $successList,
            'failed'       => $failList,
            'total_sent'   => count($successList),
            'total_failed' => count($failList),
        ], count($failList) === 0 ? 200 : 207);
    }
    
     public function previewTestEmail()
    {
        $products = $this->getJewelryProducts();
    
        return view('emails.daily-jewelry', [
            'inexpensive' => $products['inexpensive'],
            'expensive'   => $products['expensive'],
            'tags'        => ['tag' => 'salesperson'],
        ]);
    }

    // ════════════════════════════════════════════════════════════════════════
    // PRODUCTION — all subscribed Shopify customers (deduplicated)
    // ════════════════════════════════════════════════════════════════════════
    public function sendDailyJewelryEmails()
    {
        $log = EmailLog::create([
            'start_time' => now()->toDateTimeString(),
        ]);

        $customers   = $this->getSubscribedCustomers();
        $products    = $this->getJewelryProducts();
        $totalSent   = 0;
        $totalFailed = 0;
        $sentEmails  = [];

        foreach ($customers as $customer) {

            $email = strtolower(trim($customer['email'] ?? ''));

            if (empty($email) || in_array($email, $sentEmails, true)) {
                continue;
            }

            $tagspr = ['tag' => $customer['tags'] ?? ''];

            try {
                // Build BCC: admin monitors
                $bccAddresses = [];
                foreach (self::ADMIN_BCC as $adminEmail) {
                    $bccAddresses[] = ['address' => $adminEmail];
                }

                Mail::to($email, $customer['first_name'] ?? '')
                    ->bcc($bccAddresses)
                    ->send(new DailyJewelryEmail(
                        $products['inexpensive'],
                        $products['expensive'],
                        $tagspr
                    ));

                $sentEmails[] = $email;
                $totalSent++;

            } catch (\Throwable $e) {
                $totalFailed++;
                Log::error('Daily Jewelry Email Failed', [
                    'email'   => $email,
                    'message' => $e->getMessage(),
                    'file'    => $e->getFile(),
                    'line'    => $e->getLine(),
                    'trace'   => $e->getTraceAsString(),
                ]);
            }
        }

        $log->update([
            'end_time'     => now()->toDateTimeString(),
            'total_sent'   => $totalSent,
            'total_failed' => $totalFailed,
        ]);

        return response()->json([
            'message'      => 'Emails sent successfully!',
            'total_sent'   => $totalSent,
            'total_failed' => $totalFailed,
            'log'          => $log,
        ], 200);
    }

    // ════════════════════════════════════════════════════════════════════════
    // PRIVATE HELPERS
    // ════════════════════════════════════════════════════════════════════════

    private function getSubscribedCustomers(): array
    {
        $customers  = [];
        $seenEmails = [];

        $url = "https://{$this->baseUrl}/admin/api/2023-01/customers.json"
             . "?fields=email,first_name,phone,tags,notes"
             . "&accepts_marketing=true&limit=250";

        do {
            $response = Http::withHeaders([
                'X-Shopify-Access-Token' => env('SHOPIFY_ACCESS_TOKEN'),
            ])->get($url);

            if ($response->failed()) {
                Log::error("Shopify API Error: " . $response->body());
                return $customers;
            }

            foreach ($response->json()['customers'] ?? [] as $customer) {
                $email = strtolower(trim($customer['email'] ?? ''));
                if (empty($email) || in_array($email, $seenEmails, true)) {
                    continue;
                }
                $seenEmails[]  = $email;
                $customers[]   = $customer;
            }

            $url = $this->getNextPageUrl($response->header('Link'));

        } while ($url);

        return $customers;
    }

    private function getNextPageUrl(?string $linkHeader): ?string
    {
        if (!$linkHeader) return null;
        preg_match('/<(.*?)>; rel="next"/', $linkHeader, $matches);
        return $matches[1] ?? null;
    }

    private function getJewelryProducts()
    {
        $allProducts = collect();

        $endpoint = "https://{$this->baseUrl}/admin/api/2023-01/products.json"
                  . "?limit=250&status=active"
                  . "&fields=id,variants,image,title,handle,product_type,tags";

        $headers = ['X-Shopify-Access-Token' => env('SHOPIFY_ACCESS_TOKEN')];

        do {
            $response    = Http::withHeaders($headers)->get($endpoint);
            $products    = collect($response->json()['products'] ?? []);
            $allProducts = $allProducts->merge($products);

            $linkHeader = $response->header('Link');
            $nextPage   = null;

            if ($linkHeader && str_contains($linkHeader, 'rel="next"')) {
                preg_match('/<([^>]+)>; rel="next"/', $linkHeader, $matches);
                $nextPage = $matches[1] ?? null;
                $endpoint = $nextPage;
            }

        } while ($nextPage);

        $cleanedProducts = $allProducts->map(function ($product) {
            $product['price']     = isset($product['variants'][0]['price'])
                ? (float) $product['variants'][0]['price'] : 0;
            $product['image_src'] = $product['image']['src'] ?? null;
            return $product;
        })->filter(function ($product) {
            $imageSrc      = $product['image_src'] ?? '';
            $productType   = strtolower($product['product_type'] ?? '');
            $isDiamondType = str_contains($productType, 'diamond');
            return !empty($imageSrc)
                && !str_contains($imageSrc, '(no-image)')
                && !str_contains($imageSrc, 'PhotoComingSoon')
                && !$isDiamondType;
        })->sortBy('price')->values();

        $categories = [
            'earrings' => ['earring', 'earrings'],
            'rings'    => ['ring',    'rings'],
            'pendants' => ['pendant', 'pendants'],
            'bracelet' => ['bracelet','bracelets'],
        ];

        $usedInexpensive = FeaturedProduct::where('type', 'inexpensive')->pluck('product_id')->toArray();
        $usedExpensive   = FeaturedProduct::where('type', 'expensive')->pluck('product_id')->toArray();

        $inexpensiveProducts = [];
        $expensiveProducts   = [];

        foreach ($categories as $category => $keywords) {

            $categoryProducts = $cleanedProducts->filter(function ($product) use ($keywords) {
                $title = strtolower($product['title'] ?? '');
                $type  = strtolower($product['product_type'] ?? '');
                $tags  = strtolower($product['tags'] ?? '');
                foreach ($keywords as $keyword) {
                    if (str_contains($title, $keyword) ||
                        str_contains($type,  $keyword) ||
                        str_contains($tags,  $keyword)) {
                        return true;
                    }
                }
                return false;
            })->values();

            if ($categoryProducts->isEmpty()) continue;

            $poolSize = max(1, (int) ceil($categoryProducts->count() * 0.2));

            $availableInexpensive = $categoryProducts->take($poolSize)->reject(function ($p) use ($usedInexpensive) {
                return in_array($p['id'], $usedInexpensive);
            });
            $inexpensiveProduct = $availableInexpensive->isNotEmpty() ? $availableInexpensive->random() : null;

            if ($inexpensiveProduct) {
                FeaturedProduct::firstOrCreate(
                    ['product_id' => $inexpensiveProduct['id']],
                    ['type' => 'inexpensive', 'email_status' => 1]
                );
                $inexpensiveProducts[] = $inexpensiveProduct;
            }

            $availableExpensive = $categoryProducts->slice(-$poolSize)->reject(function ($p) use ($usedExpensive) {
                return in_array($p['id'], $usedExpensive);
            });
            $expensiveProduct = $availableExpensive->isNotEmpty() ? $availableExpensive->random() : null;

            if ($expensiveProduct) {
                FeaturedProduct::firstOrCreate(
                    ['product_id' => $expensiveProduct['id']],
                    ['type' => 'expensive', 'email_status' => 1]
                );
                $expensiveProducts[] = $expensiveProduct;
            }
        }

        if (count($inexpensiveProducts) > 3) {
            $inexpensiveProducts = collect($inexpensiveProducts)->shuffle()->take(3)->values()->all();
        }
        if (count($expensiveProducts) > 3) {
            $expensiveProducts = collect($expensiveProducts)->shuffle()->take(3)->values()->all();
        }

        // Diamonds
        $diamondProducts = DB::table('tbl_diamond_new')
            ->select('id','code','description','final_price','images',
                     'certificate_no','weight','shapecode','colorcode',
                     'claritycode','labcode','shade')
            ->whereNotNull('final_price')
            ->where('final_price', '>', 0)
            ->orderBy('final_price')
            ->get();

        if ($diamondProducts->isNotEmpty()) {

            $count    = $diamondProducts->count();
            $poolSize = max(3, (int) ceil($count * 0.2));

            $cheapPool        = $diamondProducts->take($poolSize);
            $cheapDiamonds    = $this->pickDistinctShapeDiamonds($cheapPool, 3);
            $selectedCheapIds = $cheapDiamonds->pluck('id')->all();

            foreach ($cheapDiamonds as $diamond) {
                $diamond                 = (array) $diamond;
                $diamond['id']           = 'diamond_' . $diamond['id'];
                $diamond['title']        = $diamond['description'];
                $diamond['price']        = $diamond['final_price'];
                $diamond['image_src']    = $diamond['images'];
                $diamond['product_type'] = 'diamond';
                $diamond['is_diamond']   = true;
                $diamond['handle']       = null;
                $diamond['variants']     = [['price' => $diamond['final_price'], 'compare_at_price' => null]];
                $diamond['images']       = [['src' => $diamond['image_src']]];
                $inexpensiveProducts[]   = $diamond;
            }

            $expensivePool     = $diamondProducts->slice(-$poolSize)->whereNotIn('id', $selectedCheapIds)->values();
            $expensiveDiamonds = $this->pickDistinctShapeDiamonds($expensivePool, 3);

            foreach ($expensiveDiamonds as $diamond) {
                $diamond                 = (array) $diamond;
                $diamond['id']           = 'diamond_' . $diamond['id'];
                $diamond['title']        = $diamond['description'];
                $diamond['price']        = $diamond['final_price'];
                $diamond['image_src']    = $diamond['images'];
                $diamond['product_type'] = 'diamond';
                $diamond['is_diamond']   = true;
                $diamond['handle']       = null;
                $diamond['variants']     = [['price' => $diamond['final_price'], 'compare_at_price' => null]];
                $diamond['images']       = [['src' => $diamond['image_src']]];
                $expensiveProducts[]     = $diamond;
            }
        }

        return [
            'inexpensive' => $inexpensiveProducts,
            'expensive'   => $expensiveProducts,
        ];
    }

    private function pickDistinctShapeDiamonds($pool, int $limit)
    {
        $shuffled   = $pool->shuffle()->values();
        $selected   = collect();
        $usedShapes = [];

        foreach ($shuffled as $diamond) {
            if ($selected->count() >= $limit) break;
            $shape = strtolower($diamond->shapecode ?? '');
            if (in_array($shape, $usedShapes, true)) continue;
            if (!$this->isImageAccessible($diamond->images ?? null)) continue;
            $selected->push($diamond);
            $usedShapes[] = $shape;
        }

        if ($selected->count() < $limit) {
            $selectedIds = $selected->pluck('id')->all();
            foreach ($shuffled as $diamond) {
                if ($selected->count() >= $limit) break;
                if (in_array($diamond->id, $selectedIds, true)) continue;
                if (!$this->isImageAccessible($diamond->images ?? null)) continue;
                $selected->push($diamond);
                $selectedIds[] = $diamond->id;
            }
        }

        return $selected;
    }

    private function isImageAccessible(?string $url): bool
    {
        if (empty($url)) return false;

        static $cache = [];
        if (array_key_exists($url, $cache)) return $cache[$url];

        try {
            $response = Http::timeout(3)->head($url);
            if (in_array($response->status(), [405, 501], true)) {
                $response = Http::timeout(3)->withHeaders(['Range' => 'bytes=0-0'])->get($url);
            }
            $ok = $response->successful();
        } catch (\Throwable $e) {
            $ok = false;
        }

        return $cache[$url] = $ok;
    }
}