<?php
/**
 * DBA Category Scorer — Assigns up to 2 categories per post based on content analysis
 *
 * How it works:
 *   1. Maintains the FULL list of approved WordPress categories (144 from admin)
 *   2. Analyzes post content (title + body text) to extract topic words
 *   3. Scores each category by keyword overlap with content
 *   4. Picks up to 2 categories with ≥85% consistency score
 *   5. Falls back to "Corporate Structuring" if nothing scores high enough
 *
 * The 85% threshold means: at least 85% of the category's defining keywords
 * must appear in the article content for it to qualify.
 */
class DBA_Category_Scorer {

    private static $instance = null;

    /**
     * Master category registry — name => slug
     * Extracted from WordPress Categories admin (all 8 pages, English only)
     */
    private $approved_categories = array(
        'Accounting'                          => 'accounting',
        'Agriculture/Agri-food'               => 'agriculture-agri-food',
        'AI/Artificial Intelligence'          => 'ai-artificial-intelligence',
        'AIF/AIFM'                            => 'aif-aifm',
        'Aircraft'                            => 'aircraft',
        'Alternative Investment Fund (AIFM)'  => 'alternative-investment-fund-aifm',
        'APA/RPA'                             => 'apa-rpa',
        'Art & Luxury'                        => 'art-luxury',
        'Artificial intelligence'             => 'artificial-intelligence',
        'Asia'                                => 'asia',
        'Asset management'                    => 'asset-management',
        'Auto Live Sports'                    => 'auto-live-sports',
        'Automotive'                          => 'automotive',
        'Autonomous Process Automation'       => 'autonomous-process-automation',
        'Bank account'                        => 'bank-account',
        'Banking'                             => 'banking',
        'Blockchain technology'               => 'blockchain-technology',
        'Brand and Society'                   => 'brand-and-society',
        'Business trip/travel'                => 'business-trip-travel',
        'Capital markets'                     => 'capital-markets',
        'Carbon credit trading'               => 'carbon-credit-trading',
        'Climate change'                      => 'climate-change',
        'Commodities'                         => 'commodities',
        'company formation'                   => 'company-formation',
        'Company formation/Business registration' => 'company-formation-business-registration',
        'Company Management'                  => 'company-management',
        'Consumer Goods'                      => 'consumer-goods',
        'Corporate Structuring'               => 'corporate-structuring',
        'Crowdfunding'                        => 'crowdfunding',
        'Crypto & Blockchain'                 => 'crypto-blockchain',
        'Crypto currencies'                   => 'crypto-currencies',
        'Customer development'                => 'customer-development',
        'Cyber – IT Security'                 => 'cyber-it-security',
        'Data center'                         => 'data-center',
        'Data centers'                        => 'data-centers',
        'Defense & Security'                  => 'defense-security',
        'Depositary/Custodian bank'           => 'depositary-custodian-bank',
        'Digital assets/Virtual currencies'   => 'digital-assets-virtual-currencies',
        'Digital infrastructures'             => 'digital-infrastructures',
        'Distressed assets'                   => 'distressed-assets',
        'Economy'                             => 'economy',
        'Electronics and Semiconductors'      => 'electronics-and-semiconductors',
        'Employment Law'                      => 'employment-law',
        'Energy'                              => 'energy',
        'Energy/Power'                        => 'energy-power',
        'Entertainment'                       => 'entertainment',
        'Entrepreneurship'                    => 'entrepreneurship',
        'Equity capital'                      => 'equity-capital',
        'ESG'                                 => 'esg',
        'Evergreen funds'                     => 'evergreen-funds',
        'Exchange-traded fund (ETF)'          => 'exchange-traded-fund-etf',
        'Export/Import trading'               => 'export-import-trading',
        'Family offices'                      => 'family-offices',
        'Fashion'                             => 'fashion',
        'Finance'                             => 'finance',
        'Fine arts'                           => 'fine-arts',
        'Fintech'                             => 'fintech',
        'Food industry'                       => 'food-industry',
        'Foreign Direct Investments'          => 'foreign-direct-investments',
        'Foreign exchange'                    => 'foreign-exchange',
        'Free zones'                          => 'free-zones',
        'Fund setup'                          => 'fund-setup',
        'Funds'                               => 'funds',
        'Gaming industry'                     => 'gaming-industry',
        'Government/Institutions'             => 'government-institutions',
        'Governments/Institutions'            => 'governments-institutions',
        'Growth Strategy'                     => 'growth-strategy',
        'Healthcare/Pharmaceutical'           => 'healthcare-pharmaceutical',
        'Hedge funds'                         => 'hedge-funds',
        'Holding companies'                   => 'holding-companies',
        'Hospitality Industry'                => 'hospitality-industry',
        'IGaming'                             => 'igaming-2',
        'Impacting investing'                 => 'impacting-investing',
        'Import-export trade'                 => 'import-export-trade',
        'Information technology'              => 'information-technology',
        'Infrastructures'                     => 'infrastructures',
        'Initial Public Offering (IPO)'       => 'initial-public-offering-ipo',
        'Intellectual Property'               => 'intellectual-property',
        'International news'                  => 'international-news',
        'Investment funds'                    => 'investment-funds',
        'Investment management'               => 'investment-management',
        'Investments'                         => 'investments',
        'Investor program'                    => 'investor-program',
        'Islamic finance'                     => 'islamic-finance',
        'Latin America'                       => 'latin-america',
        'Leadership'                          => 'leadership',
        'Life Science'                        => 'life-science',
        'Lifestyle'                           => 'lifestyle',
        'LIquidity solutions'                 => 'liquidity-solutions',
        'Live Sports'                         => 'live-sports',
        'Logistics'                           => 'logistics',
        'Luxury'                              => 'luxury',
        'Medtech'                             => 'medtech',
        'Mergers & Acquisitions'              => 'mergers-acquisitions',
        'Middle East & Africa'                => 'middle-east-africa',
        'Mining'                              => 'mining',
        'NEWS'                                => 'news',
        'Oil-Gas & Chemicals'                 => 'oil-gas-chemicals',
        'PE/VC/Business angels'               => 'pe-vc-business-angels',
        'Pension funds/Pension schemes'       => 'pension-funds-pension-schemes',
        'Personal Income Tax'                 => 'personal-income-tax',
        'Private debt/Private credit'         => 'private-debt-private-credit',
        'Private debts'                       => 'private-debts',
        'Private equity'                      => 'private-equity',
        'Professional Services'               => 'professional-services',
        'Proptech'                            => 'proptech',
        'Real estate'                         => 'real-estate',
        'Recycling'                           => 'recycling',
        'Regulated funds/UCITS'               => 'regulated-funds-ucits',
        'Reinsurance captive'                 => 'reinsurance-captive',
        'Relocation'                          => 'relocation',
        'Renewable energy'                    => 'renewable-energy',
        'Resident directorship'               => 'resident-directorship',
        'Responsible investments'             => 'responsible-investments',
        'Retail, Wholesale, Distribution'     => 'retail-wholesale-distribution',
        'Sale & Leaseback'                    => 'sale-leaseback',
        'Securitization'                      => 'securitization',
        'Senior Living'                       => 'senior-living',
        'Space industry'                      => 'space-industry',
        'Sports'                              => 'sports',
        'Startup/Unicorns'                    => 'startup-unicorns',
        'Startups'                            => 'startups',
        'Stock Exchanges'                     => 'stock-exchanges',
        'Stock market'                        => 'stock-market',
        'Tax'                                 => 'tax',
        'Technology'                          => 'technology',
        'Technology, Media & Telecom'         => 'technology-media-telecom',
        'Textiles & Apparel'                  => 'textiles-apparel',
        'Tokenization/Blockchain'             => 'tokenization-blockchain',
        'Training and Coaching'               => 'training-and-coaching',
        'UCITS'                               => 'ucits',
        'Urbanization'                        => 'urbanization',
        'Venture capital'                     => 'venture-capital',
        'Visa programs'                       => 'visa-programs',
        'Wealth Management'                   => 'wealth-management',
        'Wine market'                         => 'wine-market',
        'Yachts'                              => 'yachts',
    );

    /**
     * Extended keyword map — each category gets a set of weighted keywords
     * that help determine content relevance. These are the core terms that
     * MUST appear in the content for the category to match.
     *
     * Format: 'category_slug' => array('keyword1', 'keyword2', ...)
     * The scorer checks what % of these keywords appear in the article.
     */
    private $category_keywords = array(
        'accounting'                         => array('accounting', 'audit', 'bookkeeping', 'financial statements', 'ledger', 'accountant', 'balance sheet', 'fiscal year'),
        'agriculture-agri-food'              => array('agriculture', 'agri-food', 'farming', 'crop', 'agribusiness', 'food production', 'agricultural'),
        'ai-artificial-intelligence'         => array('artificial intelligence', 'machine learning', 'deep learning', 'neural network', 'algorithm', 'automation', 'predictive'),
        'aif-aifm'                           => array('aif', 'aifm', 'alternative investment fund', 'fund manager', 'cssf', 'aifmd'),
        'aircraft'                           => array('aircraft', 'aviation', 'jet', 'airline', 'flight', 'airplane', 'aerospace', 'pilot'),
        'alternative-investment-fund-aifm'   => array('alternative investment', 'aifm', 'fund manager', 'cssf', 'regulated fund', 'aifmd', 'depositary'),
        'apa-rpa'                            => array('apa', 'rpa', 'robotic process', 'automation', 'process automation'),
        'art-luxury'                         => array('art', 'luxury', 'gallery', 'auction', 'collection', 'fine art', 'luxury goods'),
        'artificial-intelligence'            => array('artificial intelligence', 'machine learning', 'deep learning', 'neural', 'algorithm', 'automation'),
        'asia'                               => array('asia', 'asian', 'china', 'japan', 'india', 'singapore', 'hong kong', 'southeast asia', 'korea'),
        'asset-management'                   => array('asset management', 'portfolio', 'wealth', 'fund management', 'aum', 'assets under management'),
        'automotive'                         => array('automotive', 'car', 'vehicle', 'electric vehicle', 'automobile', 'motor', 'ev', 'hybrid'),
        'bank-account'                       => array('bank account', 'banking', 'account opening', 'bank', 'deposit', 'iban', 'current account'),
        'banking'                            => array('bank', 'banking', 'credit', 'deposit', 'financial institution', 'loan', 'interest rate'),
        'blockchain-technology'              => array('blockchain', 'distributed ledger', 'smart contract', 'decentralized', 'token', 'consensus'),
        'brand-and-society'                  => array('brand', 'society', 'corporate social', 'csr', 'social responsibility', 'community', 'impact'),
        'business-trip-travel'               => array('business trip', 'travel', 'business travel', 'corporate travel', 'mobility', 'relocation'),
        'capital-markets'                    => array('capital market', 'stock', 'bond', 'equity', 'securities', 'ipo', 'listing', 'exchange'),
        'carbon-credit-trading'              => array('carbon credit', 'carbon trading', 'emissions', 'carbon offset', 'greenhouse', 'co2', 'carbon market'),
        'climate-change'                     => array('climate change', 'global warming', 'carbon', 'emissions', 'sustainability', 'paris agreement', 'climate'),
        'commodities'                        => array('commodities', 'commodity', 'raw materials', 'metals', 'oil', 'gold', 'trading', 'futures'),
        'company-formation'                  => array('company formation', 'incorporation', 'business registration', 'register company', 'set up company'),
        'company-formation-business-registration' => array('company formation', 'business registration', 'incorporation', 'register', 'set up', 'establish company'),
        'company-management'                 => array('company management', 'directorship', 'domiciliation', 'corporate governance', 'board', 'director'),
        'consumer-goods'                     => array('consumer goods', 'fmcg', 'retail', 'consumer products', 'household', 'packaged goods'),
        'corporate-structuring'              => array('corporate structuring', 'holding', 'soparfi', 'structure', 'subsidiary', 'parent company', 'spv'),
        'crowdfunding'                       => array('crowdfunding', 'crowd', 'fundraising', 'kickstarter', 'peer-to-peer', 'campaign'),
        'crypto-blockchain'                  => array('crypto', 'blockchain', 'bitcoin', 'ethereum', 'cryptocurrency', 'token', 'defi', 'digital asset'),
        'crypto-currencies'                  => array('cryptocurrency', 'crypto', 'bitcoin', 'ethereum', 'digital currency', 'token', 'coin'),
        'customer-development'               => array('customer development', 'customer', 'market validation', 'product-market fit', 'lean startup'),
        'cyber-it-security'                  => array('cybersecurity', 'security', 'data protection', 'hacking', 'firewall', 'encryption', 'cyber'),
        'data-center'                        => array('data center', 'server', 'cloud', 'colocation', 'hosting', 'infrastructure', 'computing'),
        'data-centers'                       => array('data center', 'server', 'cloud', 'colocation', 'hosting', 'digital infrastructure'),
        'defense-security'                   => array('defense', 'security', 'military', 'arms', 'defense industry', 'national security'),
        'depositary-custodian-bank'          => array('depositary', 'custodian', 'bank', 'safekeeping', 'custody', 'fund administration'),
        'digital-assets-virtual-currencies'  => array('digital asset', 'virtual currency', 'token', 'crypto', 'nft', 'digital token'),
        'digital-infrastructures'            => array('digital infrastructure', 'fiber', 'network', 'connectivity', 'telecom', 'broadband'),
        'distressed-assets'                  => array('distressed', 'non-performing', 'npl', 'workout', 'restructuring', 'insolvency', 'distressed asset'),
        'economy'                            => array('economy', 'economic', 'gdp', 'growth', 'recession', 'inflation', 'monetary', 'fiscal'),
        'electronics-and-semiconductors'     => array('semiconductor', 'chip', 'electronics', 'silicon', 'wafer', 'integrated circuit', 'transistor'),
        'employment-law'                     => array('employment law', 'labor', 'worker', 'employee', 'workplace', 'contract', 'dismissal', 'employment'),
        'energy'                             => array('energy', 'power', 'electricity', 'grid', 'generation', 'utility', 'energy sector'),
        'energy-power'                       => array('energy', 'power', 'electricity', 'utility', 'grid', 'generation', 'power plant'),
        'entertainment'                      => array('entertainment', 'media', 'streaming', 'film', 'music', 'gaming', 'content', 'studio'),
        'entrepreneurship'                   => array('entrepreneur', 'startup', 'founder', 'innovation', 'business plan', 'venture', 'entrepreneurship'),
        'equity-capital'                     => array('equity capital', 'equity', 'share capital', 'shareholders', 'stock', 'equity financing'),
        'esg'                                => array('esg', 'environmental', 'social', 'governance', 'sustainability', 'responsible', 'impact'),
        'evergreen-funds'                    => array('evergreen fund', 'open-ended', 'perpetual', 'fund', 'evergreen', 'no maturity'),
        'exchange-traded-fund-etf'           => array('etf', 'exchange-traded', 'index fund', 'tracker', 'passive', 'listed fund'),
        'export-import-trading'              => array('export', 'import', 'trade', 'customs', 'tariff', 'international trade', 'cross-border trade'),
        'family-offices'                     => array('family office', 'wealth', 'family wealth', 'succession', 'multi-family', 'single-family'),
        'fashion'                            => array('fashion', 'apparel', 'luxury fashion', 'clothing', 'textile', 'designer', 'retail fashion'),
        'finance'                            => array('finance', 'financial', 'capital', 'funding', 'credit', 'investment', 'banking'),
        'fine-arts'                          => array('fine art', 'art', 'painting', 'sculpture', 'gallery', 'museum', 'collection', 'auction'),
        'fintech'                            => array('fintech', 'financial technology', 'payment', 'neobank', 'digital banking', 'regtech'),
        'food-industry'                      => array('food industry', 'food', 'beverage', 'food processing', 'restaurant', 'food production'),
        'foreign-direct-investments'         => array('foreign direct investment', 'fdi', 'cross-border investment', 'inward investment', 'foreign investor'),
        'foreign-exchange'                   => array('foreign exchange', 'forex', 'currency', 'exchange rate', 'fx', 'currency trading'),
        'free-zones'                         => array('free zone', 'special economic zone', 'tax-free zone', 'freeport', 'free trade zone'),
        'fund-setup'                         => array('fund setup', 'fund formation', 'fund launch', 'fund structuring', 'fund registration'),
        'funds'                              => array('fund', 'investment fund', 'mutual fund', 'fund management', 'pooled investment'),
        'gaming-industry'                    => array('gaming', 'video game', 'esports', 'game', 'console', 'mobile gaming'),
        'government-institutions'            => array('government', 'institution', 'public sector', 'regulation', 'ministry', 'authority'),
        'governments-institutions'           => array('government', 'institution', 'public sector', 'regulation', 'ministry', 'authority'),
        'growth-strategy'                    => array('growth strategy', 'growth', 'expansion', 'scale', 'market entry', 'strategy', 'business development'),
        'healthcare-pharmaceutical'          => array('healthcare', 'pharmaceutical', 'pharma', 'drug', 'medical', 'clinical', 'biotech', 'health'),
        'hedge-funds'                        => array('hedge fund', 'alternative', 'absolute return', 'long-short', 'macro', 'hedge'),
        'holding-companies'                  => array('holding company', 'holding', 'soparfi', 'parent company', 'subsidiary', 'group structure'),
        'hospitality-industry'               => array('hospitality', 'hotel', 'tourism', 'resort', 'travel', 'accommodation'),
        'igaming-2'                          => array('igaming', 'online gambling', 'betting', 'casino', 'gambling', 'gaming license'),
        'impacting-investing'                => array('impact investing', 'social impact', 'esg', 'responsible investment', 'impact fund'),
        'import-export-trade'                => array('import', 'export', 'trade', 'customs', 'international trade', 'cross-border'),
        'information-technology'             => array('information technology', 'software', 'hardware', 'systems', 'digital', 'computing'),
        'infrastructures'                    => array('infrastructure', 'construction', 'transport', 'road', 'bridge', 'utility', 'public works'),
        'initial-public-offering-ipo'        => array('ipo', 'initial public offering', 'listing', 'stock exchange', 'going public', 'flotation'),
        'intellectual-property'              => array('intellectual property', 'patent', 'trademark', 'copyright', 'ip', 'license', 'royalty'),
        'international-news'                 => array('international', 'global', 'world', 'geopolitics', 'foreign', 'cross-border', 'news'),
        'investment-funds'                   => array('investment fund', 'fund', 'sicav', 'raif', 'ucits', 'sif', 'fund management'),
        'investment-management'              => array('investment management', 'portfolio management', 'asset allocation', 'wealth management'),
        'investments'                        => array('investment', 'invest', 'capital', 'portfolio', 'return', 'allocation', 'diversification'),
        'investor-program'                   => array('investor program', 'residency', 'visa', 'golden visa', 'citizenship', 'investor visa'),
        'islamic-finance'                    => array('islamic finance', 'sharia', 'sukuk', 'halal', 'islamic banking', 'murabaha'),
        'latin-america'                      => array('latin america', 'brazil', 'mexico', 'argentina', 'chile', 'colombia', 'south america'),
        'leadership'                         => array('leadership', 'management', 'executive', 'ceo', 'governance', 'leader'),
        'life-science'                       => array('life science', 'biotech', 'pharmaceutical', 'clinical', 'research', 'biology'),
        'lifestyle'                          => array('lifestyle', 'luxury', 'travel', 'wellness', 'living', 'high-net-worth'),
        'liquidity-solutions'                => array('liquidity', 'liquidity solution', 'cash flow', 'liquid', 'redemption', 'secondary market'),
        'live-sports'                        => array('live sports', 'match', 'game', 'tournament', 'league', 'sports coverage'),
        'logistics'                          => array('logistics', 'supply chain', 'warehouse', 'freight', 'shipping', 'distribution'),
        'luxury'                             => array('luxury', 'premium', 'high-end', 'exclusive', 'luxury goods', 'luxury brand'),
        'medtech'                            => array('medtech', 'medical device', 'medical technology', 'health tech', 'diagnostic'),
        'mergers-acquisitions'               => array('merger', 'acquisition', 'takeover', 'due diligence', 'deal', 'buyout', 'consolidation'),
        'middle-east-africa'                 => array('middle east', 'africa', 'gulf', 'uae', 'saudi', 'dubai', 'african'),
        'mining'                             => array('mining', 'mineral', 'ore', 'extraction', 'mine', 'metals', 'rare earth'),
        'news'                               => array('news', 'breaking', 'update', 'announcement', 'press release', 'headline'),
        'oil-gas-chemicals'                  => array('oil', 'gas', 'chemical', 'petroleum', 'refinery', 'petrochemical', 'energy'),
        'pe-vc-business-angels'              => array('private equity', 'venture capital', 'business angel', 'angel investor', 'seed', 'series'),
        'pension-funds-pension-schemes'      => array('pension fund', 'pension scheme', 'retirement', 'pension', 'annuity', 'defined benefit'),
        'personal-income-tax'                => array('personal income tax', 'income tax', 'tax rate', 'tax bracket', 'personal tax', 'salary tax'),
        'private-debt-private-credit'        => array('private debt', 'private credit', 'direct lending', 'mezzanine', 'credit fund', 'loan fund'),
        'private-debts'                      => array('private debt', 'debt', 'lending', 'credit', 'loan', 'fixed income'),
        'private-equity'                     => array('private equity', 'buyout', 'leveraged', 'fund', 'portfolio company', 'exit', 'lbo'),
        'professional-services'              => array('professional services', 'consulting', 'advisory', 'law firm', 'consultancy', 'adviser'),
        'proptech'                           => array('proptech', 'property technology', 'real estate tech', 'smart building', 'property'),
        'real-estate'                        => array('real estate', 'property', 'commercial real estate', 'residential', 'reit', 'building'),
        'recycling'                          => array('recycling', 'waste', 'circular economy', 'sustainability', 'waste management'),
        'regulated-funds-ucits'              => array('regulated fund', 'ucits', 'cssf', 'fund regulation', 'compliant fund', 'passporting'),
        'reinsurance-captive'                => array('reinsurance', 'captive', 'insurance', 'risk transfer', 'underwriting', 'captive insurance'),
        'relocation'                         => array('relocation', 'relocate', 'move', 'expatriate', 'immigration', 'residence permit'),
        'renewable-energy'                   => array('renewable energy', 'solar', 'wind', 'green energy', 'clean energy', 'sustainable energy'),
        'resident-directorship'              => array('resident directorship', 'resident director', 'nominee director', 'local director', 'directorship'),
        'responsible-investments'            => array('responsible investment', 'sri', 'sustainable', 'esg', 'green bond', 'impact'),
        'retail-wholesale-distribution'      => array('retail', 'wholesale', 'distribution', 'supply chain', 'store', 'e-commerce'),
        'sale-leaseback'                     => array('sale leaseback', 'leaseback', 'sale and leaseback', 'lease', 'asset monetization'),
        'securitization'                     => array('securitization', 'spv', 'abs', 'mortgage-backed', 'securitize', 'structured finance', 'tranche'),
        'senior-living'                      => array('senior living', 'elderly', 'retirement home', 'care home', 'aging', 'assisted living'),
        'space-industry'                     => array('space', 'satellite', 'orbit', 'launch', 'aerospace', 'space industry', 'rocket'),
        'sports'                             => array('sports', 'athlete', 'team', 'league', 'competition', 'championship', 'sport'),
        'startup-unicorns'                   => array('startup', 'unicorn', 'scale-up', 'valuation', 'billion', 'growth', 'venture'),
        'startups'                           => array('startup', 'founder', 'seed', 'venture', 'innovation', 'incubator', 'accelerator'),
        'stock-exchanges'                    => array('stock exchange', 'exchange', 'listing', 'ipo', 'trading', 'bourse', 'market'),
        'stock-market'                       => array('stock market', 'stock', 'share', 'equity', 'market', 'index', 'trading'),
        'tax'                                => array('tax', 'taxation', 'tax rate', 'withholding', 'vat', 'tax treaty', 'deduction'),
        'technology'                         => array('technology', 'tech', 'digital', 'software', 'innovation', 'platform', 'saas'),
        'technology-media-telecom'           => array('technology', 'media', 'telecom', 'telecommunications', 'broadcasting', 'tmt'),
        'textiles-apparel'                   => array('textile', 'apparel', 'fabric', 'clothing', 'fashion', 'garment', 'manufacturing'),
        'tokenization-blockchain'            => array('tokenization', 'blockchain', 'token', 'digital asset', 'smart contract', 'dlt'),
        'training-and-coaching'              => array('training', 'coaching', 'development', 'skill', 'education', 'workshop'),
        'ucits'                              => array('ucits', 'passporting', 'regulated fund', 'cssf', 'eu fund', 'undertaking'),
        'urbanization'                       => array('urbanization', 'urban', 'city', 'smart city', 'urban development', 'metropolitan'),
        'venture-capital'                    => array('venture capital', 'vc', 'seed', 'series a', 'series b', 'startup funding', 'venture'),
        'visa-programs'                      => array('visa', 'residence permit', 'golden visa', 'immigration', 'work permit', 'visa program'),
        'wealth-management'                  => array('wealth management', 'wealth', 'private banking', 'hnwi', 'family office', 'portfolio'),
        'wine-market'                        => array('wine', 'vineyard', 'winery', 'wine market', 'viticulture', 'vintage'),
        'yachts'                             => array('yacht', 'ship', 'marine', 'vessel', 'boat', 'maritime', 'sailing'),
    );

    public static function get_instance() {
        if ( null === self::$instance ) self::$instance = new self();
        return self::$instance;
    }

    /**
     * Get the full approved categories list
     */
    public function get_approved_categories() {
        return $this->approved_categories;
    }

    /**
     * Get category keywords map
     */
    public function get_category_keywords() {
        return $this->category_keywords;
    }

    /**
     * Score and assign up to 2 categories from the approved list.
     *
     * @param string $title       Post title
     * @param string $content_html Post body HTML
     * @param string $theme       Generation theme
     * @param string $ai_category Category suggested by OpenAI (used as hint)
     * @return array Array of WP term_ids (1-2 categories)
     */
    public function assign_categories( $title, $content_html, $theme = '', $ai_category = '' ) {

        // Build the text corpus for analysis
        $text = strtolower( $title . ' ' . wp_strip_all_tags( $content_html ) . ' ' . $theme );

        // Score every approved category
        $scores = array();

        foreach ( $this->approved_categories as $cat_name => $cat_slug ) {
            $keywords = isset( $this->category_keywords[ $cat_slug ] ) ? $this->category_keywords[ $cat_slug ] : array();

            if ( empty( $keywords ) ) {
                // Fallback: derive keywords from category name
                $keywords = $this->derive_keywords_from_name( $cat_name );
            }

            $score = $this->calculate_consistency_score( $text, $keywords, $cat_name );
            $scores[ $cat_slug ] = array(
                'name'  => $cat_name,
                'slug'  => $cat_slug,
                'score' => $score,
            );
        }

        // Sort by score descending
        usort( $scores, function( $a, $b ) {
            if ( abs( $b['score'] - $a['score'] ) < 0.001 ) return 0;
            return $b['score'] > $a['score'] ? 1 : -1;
        });

        // Pick up to 2 categories with >= 85% consistency
        $threshold = 0.85;
        $selected  = array();

        foreach ( $scores as $entry ) {
            if ( count( $selected ) >= 2 ) break;
            if ( $entry['score'] >= $threshold ) {
                $selected[] = $entry;
            }
        }

        // If AI suggested a category that's in our approved list and scores >= 70%, add it as a candidate
        if ( ! empty( $ai_category ) && count( $selected ) < 2 ) {
            $ai_slug = sanitize_title( $ai_category );
            $ai_found = false;
            foreach ( $selected as $s ) {
                if ( $s['slug'] === $ai_slug ) { $ai_found = true; break; }
            }
            if ( ! $ai_found ) {
                foreach ( $scores as $entry ) {
                    if ( $entry['slug'] === $ai_slug && $entry['score'] >= 0.70 ) {
                        $selected[] = $entry;
                        break;
                    }
                }
            }
        }

        // Fallback: if nothing scored >= 85%, pick the highest scorer above 50%, or default
        if ( empty( $selected ) ) {
            foreach ( $scores as $entry ) {
                if ( $entry['score'] >= 0.50 ) {
                    $selected[] = $entry;
                    break;
                }
            }
        }

        // Ultimate fallback
        if ( empty( $selected ) ) {
            $selected[] = array( 'name' => 'Corporate Structuring', 'slug' => 'corporate-structuring', 'score' => 0 );
        }

        // Resolve to WP term IDs
        $term_ids = array();
        foreach ( $selected as $cat ) {
            $term = get_term_by( 'slug', $cat['slug'], 'category' );
            if ( $term ) {
                $term_ids[] = $term->term_id;
                error_log( 'DBA Category Scorer: Assigned "' . $cat['name'] . '" (slug: ' . $cat['slug'] . ', score: ' . round( $cat['score'] * 100 ) . '%)' );
            } else {
                // Category exists in our list but not yet in WP — create it
                $result = wp_insert_term( $cat['name'], 'category', array( 'slug' => $cat['slug'] ) );
                if ( ! is_wp_error( $result ) ) {
                    $term_ids[] = $result['term_id'];
                    error_log( 'DBA Category Scorer: Created & assigned "' . $cat['name'] . '" (slug: ' . $cat['slug'] . ', score: ' . round( $cat['score'] * 100 ) . '%)' );
                }
            }
        }

        if ( empty( $term_ids ) ) {
            $term_ids = array( 1 ); // Uncategorized fallback
        }

        return $term_ids;
    }

    /**
     * Calculate consistency score between content text and category keywords.
     *
     * Score = (matched_keywords / total_keywords) * weight_boost
     *
     * Weight boost accounts for:
     *   - Category name appearing directly in text (strong signal)
     *   - Multiple keyword matches (compound relevance)
     *   - Keyword frequency (appearing many times = stronger)
     */
    private function calculate_consistency_score( $text, $keywords, $cat_name ) {
        if ( empty( $keywords ) ) return 0;

        $total     = count( $keywords );
        $matched   = 0;
        $freq_bonus = 0;

        foreach ( $keywords as $kw ) {
            $kw_lower = strtolower( $kw );
            if ( strpos( $text, $kw_lower ) !== false ) {
                $matched++;
                // Count frequency for bonus
                $count = substr_count( $text, $kw_lower );
                if ( $count >= 3 ) {
                    $freq_bonus += 0.05; // High frequency = strong topic
                } elseif ( $count >= 2 ) {
                    $freq_bonus += 0.02;
                }
            }
        }

        if ( $matched === 0 ) return 0;

        // Base score: what % of category keywords appear in text
        $base_score = $matched / $total;

        // Category name boost: if the exact category name appears in text
        $cat_name_lower = strtolower( $cat_name );
        // Remove special chars for matching
        $cat_name_clean = strtolower( preg_replace( '/[^a-z0-9\s]/', '', $cat_name ) );
        $name_boost = 0;
        if ( strpos( $text, $cat_name_lower ) !== false || strpos( $text, $cat_name_clean ) !== false ) {
            $name_boost = 0.15;
        }

        // Multi-match boost: more keywords matched = exponentially more relevant
        $multi_boost = 0;
        if ( $matched >= 4 ) {
            $multi_boost = 0.10;
        } elseif ( $matched >= 3 ) {
            $multi_boost = 0.05;
        }

        $final_score = min( 1.0, $base_score + $name_boost + $multi_boost + $freq_bonus );

        return $final_score;
    }

    /**
     * Derive keywords from a category name when no keyword map entry exists
     */
    private function derive_keywords_from_name( $cat_name ) {
        $words = preg_split( '/[\s\/&,\-–]+/', strtolower( $cat_name ) );
        $noise = array( 'the', 'and', 'for', 'with', 'of', 'in', 'a', 'an' );
        $result = array();
        foreach ( $words as $w ) {
            $w = trim( $w );
            if ( strlen( $w ) >= 3 && ! in_array( $w, $noise ) ) {
                $result[] = $w;
            }
        }
        // Also add the full category name as a keyword
        $result[] = strtolower( $cat_name );
        return array_unique( $result );
    }

    /**
     * Get all category names as a comma-separated string (for prompts)
     */
    public function get_category_names_string() {
        return implode( ', ', array_keys( $this->approved_categories ) );
    }

    /**
     * Get categories for admin display — name, slug, and WP post count
     */
    public function get_categories_for_admin() {
        $result = array();
        foreach ( $this->approved_categories as $name => $slug ) {
            $term = get_term_by( 'slug', $slug, 'category' );
            $result[] = array(
                'name'  => $name,
                'slug'  => $slug,
                'count' => $term ? $term->count : 0,
                'exists' => (bool) $term,
            );
        }
        return $result;
    }
}
