<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use App\Http\Traits\CrulRequest;

class IntegrateStores extends Command
{
    use CrulRequest;
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'turboly:integrateStores {--all : Sync all stores, not just updated ones}';
    protected $url = '';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Synchronize stores from Turboly API to local database';

    /**
     * The base URL for the Turboly API
     *
     * @var string
     */
    protected $apiUrl = '/api/v1/stores';

    /**
     * Default password for new users
     *
     * @var string
     */
    protected $defaultPassword = 'codelabs123';

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $this->info('Starting Turboly stores synchronization...');

        try {
            // Get the last sync time if not forcing full sync
            $lastSync = $this->option('all') ? '2000-01-01' :
                DB::connection('mysqlUser')->table('user_site')->max('updated_at') ?? '2000-01-01';

            // Fetch stores from Turboly API (with pagination)
            $stores = $this->fetchAllStores($lastSync);

            if (empty($stores)) {
                $this->info('No stores to synchronize.');
                return 0;
            }

            $this->info(sprintf('Found %d stores to process...', count($stores)));

            $bar = $this->output->createProgressBar(count($stores));
            $bar->start();

            foreach ($stores as $store) {
                try {
                    $this->processStore($store);
                } catch (\Exception $e) {
                    $this->error(sprintf('\nError processing store %s: %s', $store['id'] ?? 'unknown', $e->getMessage()));
                }

                $bar->advance();
            }

            $bar->finish();
            $this->info('\nStores synchronization completed successfully.');
            return 0;
        } catch (\Exception $e) {
            $this->error('Synchronization failed: ' . $e->getMessage());
            return 1;
        }
    }

    /**
     * Process a single store: Create or Update
     *
     * @param array $store
     */
    protected function processStore($store)
    {
        // Sanitize data
        $rawName = (string)($store['name'] ?? 'store');
        
        // Site Name
        $siteName = preg_replace('/[^A-Za-z0-9 ]/', '', $rawName);
        $siteName = trim(preg_replace('/\s+/', ' ', $siteName));
        if ($siteName === '') { $siteName = 'Store '.($store['id'] ?? ''); }

        // Address Mapping (as strings)
        $siteAddress = $store['address'] ?? '';
        $siteCity = $store['city'] ?? '';
        $sitePhone = $store['phone'] ?? '';
        
        // Append province to address or keep it separate if needed, usually address contains street
        // For this requirement, we store explicit string values in their respective columns
        // Verify if API provides 'province'
        $province = $store['province'] ?? ''; 
        if (!empty($province)) {
             // Optionally append province to address if no specific column for it as string (user_site has province_id as int)
             // or just keep it in address. user_site only has site_city, site_address. 
             // Let's append to address for completeness if not in city
             $siteAddress .= ($siteAddress ? ', ' : '') . $province;
        }

        // Open Days/Hours (Defaults if not present)
        $siteOpenHours = $store['open_hours'] ?? '08:00-17:00,08:00-17:00,08:00-17:00,08:00-17:00,08:00-17:00,08:00-17:00,08:00-17:00';
        $siteOpenDays  = $store['open_days'] ?? 'sun,mon,tue,wed,thu,fri,sat';

        // Managers
        $managers = $store['store_managers'] ?? [];
        $siteManager = 'admin'; // Default fallback
        if (!empty($managers) && isset($managers[0]['name'])) {
            $siteManager = $managers[0]['name'];
        }

        // Lat/Long
        $siteLatitude = $store['latitude'] ?? '0';
        $siteLongitude = $store['longitude'] ?? '0';

        // Check if store already exists
        $existingSite = DB::connection('mysqlUser')->table('user_site')
            ->where('store_id', $store['id'])
            ->first();

        if ($existingSite) {
            // UPDATE existing site
            DB::connection('mysqlUser')->table('user_site')
                ->where('user_site_id', $existingSite->user_site_id)
                ->update([
                    'site_name' => $siteName,
                    'site_address' => $siteAddress,
                    'site_city' => $siteCity,
                    'site_phone' => $sitePhone,
                    'site_manager' => $siteManager,
                    'site_latitude' => $siteLatitude,
                    'site_longitude' => $siteLongitude,
                    'is_ecommerce' => $store['is_ecommerce'] ?? 0,
                    'is_tax' => 0,
                    'site_open_days' => $siteOpenDays,
                    'site_open_hours' => $siteOpenHours,
                    'updated_at' => date('Y-m-d H:i:s'),
                ]);
            // $this->info(sprintf('\nUpdated store: %s', $siteName));
        } else {
            // CREATE new site
            DB::connection('mysqlUser')->transaction(function () use ($store, $siteName, $siteAddress, $siteCity, $sitePhone, $siteOpenDays, $siteOpenHours, $siteManager, $siteLatitude, $siteLongitude) {
                
                // 1. User Creation/Lookup
                $userId = $this->getOrCreateUser($store);

                // 2. Insert user_site
                DB::connection('mysqlUser')->table('user_site')->insert([
                    'user_id' => $userId,
                    'client_id' => 63, // Hardcoded as per original
                    'store_id' => $store['id'],
                    'is_ecommerce' => $store['is_ecommerce'] ?? 0,
                    'is_tax' => 0,
                    'site_name' => $siteName,
                    'site_address' => $siteAddress,
                    'site_city' => $siteCity,
                    'site_phone' => $sitePhone,
                    'site_latitude' => $siteLatitude,
                    'site_longitude' => $siteLongitude,
                    'site_image' => null,
                    'site_open_days' => $siteOpenDays,
                    'site_open_hours' => $siteOpenHours,
                    'site_manager' => $siteManager,
                    'remark' => 'Synced from Turboly',
                    'province_id' => 0, // Hardcoded 0
                    'city_id' => 0,     // Hardcoded 0
                    'created_at' => date('Y-m-d H:i:s'),
                    'updated_at' => date('Y-m-d H:i:s'),
                ]);

                $this->info(sprintf('\nCreated new store: %s (ID: %s)', $siteName, $store['id']));
            });
        }
    }

    /**
     * Get existing user ID or create a new user for the store
     * 
     * @param array $store
     * @return int User ID
     */
    protected function getOrCreateUser($store)
    {
        $rawName = (string)($store['name'] ?? 'store');
        $username = preg_replace('/[^A-Za-z0-9]/', '', $rawName);
        if ($username === '') { $username = 'store'.($store['id'] ?? ''); }
        $email = strtolower($username) . '@rotary.com';

        // Check if user exists by email (more unique than username potentially) or username
        $existingUser = DB::connection('mysqlUser')->table('users')
            ->where('email', $email)
            ->orWhere('username', $username)
            ->first();

        if ($existingUser) {
            return $existingUser->user_id;
        }

        // Create new user
        return DB::connection('mysqlUser')->table('users')->insertGetId([
            'username' => $username,
            'email' => $email,
            'password' => Hash::make($this->defaultPassword),
            'token' => Str::random(60),
            'user_group_id' => 3,
            'photo' => 'user-1759458194.png',
            'created_at' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s'),
        ]);
    }

    /**
     * Fetch all stores from Turboly API with pagination
     *
     * @param string $modifiedAfter
     * @return array
     */
    protected function fetchAllStores($modifiedAfter)
    {
        $this->url = $this->apiUrl;
        $allStores = [];
        $page = 1;
        $hasMore = true;

        // If force all is used, we might want to ignore modifiedAfter, but the command already sets it to 2000-01-01
        // However, looking at the code, we actually commented out 'modified_after' in the filter.
        // So effectively it IS fetching everything.
        // Let's make sure we log the total count.

        while ($hasMore) {
            $filter = [
                // 'modified_after' => $modifiedAfter, // Keep commented to ensure we get ALL stores
                'per_page' => 100,
                'page' => $page,
            ];

            $this->info("Fetching page $page...");
            try {
                $response = $this->sendRequest('', [], $filter, 'GET');
            } catch (\Exception $e) {
                $this->error("Failed to fetch page $page: " . $e->getMessage());
                // Break or retry? Let's break to avoid infinite loop on error
                break;
            }

            if ($response['status'] != '200') {
                $this->error('Failed to fetch stores on page ' . $page . ': ' . ($response['message'] ?? 'Unknown error'));
                break;
            }

            // Correctly parse response structure
            // API Response: { status: 200, response: { stores: [...], meta: ... } }
            // So $response['response'] contains 'stores'
            $data = $response['response'] ?? [];
            $pageStores = $data['stores'] ?? [];
            
            if (empty($pageStores)) {
                $hasMore = false;
            } else {
                $allStores = array_merge($allStores, $pageStores);
                
                $count = count($pageStores);
                $this->info("Page $page: Fetched $count stores.");

                // If less than per_page, we are done
                if ($count < 100) {
                    $hasMore = false;
                } else {
                    $page++;
                }
            }
        }

        return $allStores;
    }
}
