/**
 * PrimeBridge Generator — Dynamic Data Layer V2
 * ==============================================
 * Generates realistic, unique data on the fly for the simulation engine.
 * Eliminates repetitive patterns by composing User + Action + Value + Country
 * dynamically instead of pulling from static JSON templates.
 *
 * Capabilities:
 *   - 2000+ synthetic identities (names from 15 cultural regions)
 *   - Real country names with flag emoji
 *   - Realistic portfolio values, deposits, withdrawals, profit amounts
 *   - Relative timestamps ("2 minutes ago")
 *   - Trading pairs, sector names, instruments, portfolio packages
 *   - Weighted probability selection
 *
 * @namespace PrimeBridge.generator
 * @version 1.0.0
 */
(function () {
  'use strict';

  window.PrimeBridge = window.PrimeBridge || {};

  /* ------------------------------------------------------------------ */
  /*  Cultural Name Pools                                                 */
  /*  ~2000 names across 15 regions, each with first + last               */
  /* ------------------------------------------------------------------ */

  var NAME_POOLS = {
    western: {
      first: [
        'James', 'Mary', 'Robert', 'Patricia', 'Michael', 'Jennifer', 'David', 'Linda',
        'William', 'Elizabeth', 'Richard', 'Susan', 'Joseph', 'Jessica', 'Thomas', 'Sarah',
        'Charles', 'Karen', 'Christopher', 'Lisa', 'Daniel', 'Nancy', 'Matthew', 'Betty',
        'Anthony', 'Margaret', 'Mark', 'Sandra', 'Donald', 'Ashley', 'Steven', 'Dorothy',
        'Paul', 'Kimberly', 'Andrew', 'Emily', 'Joshua', 'Donna', 'Kenneth', 'Michelle',
        'Kevin', 'Carol', 'Brian', 'Amanda', 'George', 'Melissa', 'Timothy', 'Deborah',
        'Ronald', 'Stephanie', 'Edward', 'Rebecca', 'Jason', 'Sharon', 'Jeffrey', 'Laura',
        'Ryan', 'Cynthia', 'Jacob', 'Kathleen', 'Gary', 'Amy', 'Nicholas', 'Shirley',
        'Eric', 'Angela', 'Jonathan', 'Helen', 'Stephen', 'Anna', 'Larry', 'Brenda',
        'Justin', 'Pamela', 'Scott', 'Nicole', 'Brandon', 'Katherine', 'Samuel', 'Samantha',
        'Raymond', 'Christine'
      ],
      last: [
        'Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis',
        'Rodriguez', 'Martinez', 'Hernandez', 'Lopez', 'Gonzalez', 'Wilson', 'Anderson',
        'Thomas', 'Taylor', 'Moore', 'Jackson', 'Martin', 'Lee', 'Perez', 'Thompson',
        'White', 'Harris', 'Sanchez', 'Clark', 'Ramirez', 'Lewis', 'Robinson', 'Walker',
        'Young', 'Allen', 'King', 'Wright', 'Scott', 'Torres', 'Nguyen', 'Hill', 'Flores',
        'Green', 'Adams', 'Nelson', 'Baker', 'Hall', 'Rivera', 'Campbell', 'Mitchell',
        'Carter', 'Roberts'
      ]
    },
    nigerian: {
      first: [
        'Chinedu', 'Amina', 'Emeka', 'Fatima', 'Oluwaseun', 'Ngozi', 'Tunde', 'Chiamaka',
        'Kelechi', 'Yetunde', 'Olumide', 'Adaeze', 'Chidi', 'Zainab', 'Ebere', 'Ayodele',
        'Chibuzo', 'Ijeoma', 'Uchenna', 'Olamide', 'Obinna', 'Chisom', 'Nnamdi', 'Bukola',
        'Chukwudi', 'Ekemini', 'Ifeanyi', 'Jumoke', 'Chinonso', 'Omotola', 'Akachi', 'Folake',
        'Chimamanda', 'Okechukwu', 'Chioma', 'Ebuka', 'Adaeze', 'Chibuike', 'Oluwafemi',
        'Ndidi', 'Chizoba', 'Tochukwu', 'Nkiruka', 'Onyeka', 'Chima', 'Simisola'
      ],
      last: [
        'Okafor', 'Nwosu', 'Adebayo', 'Okonkwo', 'Eze', 'Ogunlade', 'Bello', 'Uche',
        'Ogundipe', 'Abubakar', 'Okeke', 'Adeyemi', 'Muhammed', 'Nwachukwu', 'Olatunji',
        'Ibrahim', 'Okoro', 'Adegoke', 'Nwankwo', 'Oyewole', 'Chukwu', 'Afolabi',
        'Okpara', 'Adegbola', 'Nwogu', 'Ogunleye', 'Umeh', 'Adeniran', 'Okereke',
        'Onyema', 'Nduka', 'Adewale', 'Ogbu', 'Nze', 'Okafor'
      ]
    },
    indian: {
      first: [
        'Arjun', 'Priya', 'Rahul', 'Ananya', 'Vikram', 'Neha', 'Rohan', 'Aisha',
        'Aarav', 'Kavya', 'Ishaan', 'Meera', 'Raj', 'Sanya', 'Amit', 'Divya',
        'Karan', 'Pooja', 'Nikhil', 'Anjali', 'Sahil', 'Riya', 'Varun', 'Sneha',
        'Ravi', 'Shreya', 'Manoj', 'Bhavna', 'Suresh', 'Lakshmi', 'Deepak', 'Radhika',
        'Vivek', 'Sunita', 'Ankur', 'Kiran', 'Pranav', 'Swati', 'Harsh', 'Anita',
        'Gaurav', 'Nandini', 'Tarun', 'Sonia', 'Kunal', 'Asha', 'Akash', 'Deepika',
        'Yash', 'Pallavi'
      ],
      last: [
        'Sharma', 'Verma', 'Patel', 'Singh', 'Mehta', 'Kumar', 'Gupta', 'Reddy',
        'Joshi', 'Nair', 'Kapoor', 'Malhotra', 'Agarwal', 'Iyer', 'Rao', 'Bose',
        'Chopra', 'Desai', 'Dutta', 'Ghosh', 'Jain', 'Kohli', 'Mahajan', 'Menon',
        'Mishra', 'Murthy', 'Naidu', 'Pillai', 'Prasad', 'Saxena', 'Sethi', 'Sundaram',
        'Tandon', 'Trivedi', 'Vohra', 'Yadav', 'Srinivasan', 'Bhatt', 'Choudhury'
      ]
    },
    chinese: {
      first: [
        'Wei', 'Mei', 'Jun', 'Xia', 'Lei', 'Yan', 'Peng', 'Jing', 'Feng', 'Li',
        'Hao', 'Lin', 'Ming', 'Chen', 'Tao', 'Ning', 'Kai', 'Fang', 'Jian', 'Hong',
        'Zhi', 'Xin', 'Bo', 'Hua', 'Yang', 'Yu', 'Gang', 'Ping', 'Long', 'Yun',
        'Bin', 'Ting', 'Qiang', 'Lan', 'Chao', 'Ling', 'Dong', 'Ying', 'Xiang', 'Juan'
      ],
      last: [
        'Wang', 'Li', 'Zhang', 'Liu', 'Chen', 'Yang', 'Huang', 'Zhao', 'Wu', 'Zhou',
        'Xu', 'Sun', 'Ma', 'Zhu', 'Hu', 'Lin', 'Guo', 'He', 'Gao', 'Luo',
        'Liang', 'Song', 'Tang', 'Han', 'Deng', 'Cao', 'Peng', 'Ceng', 'Xiao', 'Tian',
        'Dong', 'Pan', 'Yuan', 'Cai', 'Jiang', 'Yu', 'Dai', 'Xia', 'Fang', 'Shen'
      ]
    },
    japanese: {
      first: [
        'Hiroshi', 'Yuki', 'Kenji', 'Sakura', 'Takashi', 'Aiko', 'Satoshi', 'Miyuki',
        'Kaito', 'Rin', 'Daiki', 'Yuna', 'Ryo', 'Hina', 'Sho', 'Asuka', 'Yuto', 'Nao',
        'Haruki', 'Misaki', 'Ren', 'Chie', 'Kazuki', 'Aimi', 'Shin', 'Saki', 'Taro',
        'Momo', 'Riku', 'Koharu', 'Akira', 'Riko', 'Kenta', 'Mai', 'Yoshiki', 'Eri',
        'Sora', 'Tomomi', 'Hayato', 'Natsuki'
      ],
      last: [
        'Sato', 'Suzuki', 'Takahashi', 'Tanaka', 'Watanabe', 'Ito', 'Yamamoto', 'Nakamura',
        'Ogawa', 'Kato', 'Yoshida', 'Yamada', 'Sasaki', 'Yamaguchi', 'Matsumoto', 'Inoue',
        'Kimura', 'Hayashi', 'Shimizu', 'Saito', 'Abe', 'Ishikawa', 'Mori', 'Fujita',
        'Hashimoto', 'Otsuka', 'Yamashita', 'Ishii', 'Hasegawa', 'Sakamoto'
      ]
    },
    german: {
      first: [
        'Lukas', 'Sophie', 'Felix', 'Hannah', 'Leon', 'Emma', 'Maximilian', 'Anna',
        'Jonas', 'Lena', 'Tim', 'Lea', 'Niklas', 'Mia', 'Philipp', 'Julia', 'Fabian',
        'Laura', 'Simon', 'Sarah', 'Benedikt', 'Lisa', 'David', 'Clara', 'Tobias',
        'Marie', 'Johann', 'Katharina', 'Stefan', 'Sabine', 'Klaus', 'Ingrid', 'Peter',
        'Ursula', 'Thomas', 'Renate', 'Wolfgang', 'Monika'
      ],
      last: [
        'Mueller', 'Schmidt', 'Schneider', 'Fischer', 'Weber', 'Wagner', 'Becker', 'Hoffmann',
        'Schaefer', 'Koch', 'Bauer', 'Richter', 'Klein', 'Wolf', 'Schroeder', 'Neumann',
        'Schwarz', 'Zimmermann', 'Braun', 'Krueger', 'Hofmann', 'Hartmann', 'Lange', 'Werner',
        'Schmitz', 'Krause', 'Maier', 'Lehmann', 'Huber', 'Kaiser', 'Fuchs', 'Peters'
      ]
    },
    french: {
      first: [
        'Lucas', 'Emma', 'Hugo', 'Lea', 'Gabriel', 'Manon', 'Jules', 'Chloe',
        'Adam', 'Camille', 'Arthur', 'Sarah', 'Louis', 'Pauline', 'Nathan', 'Lina',
        'Mathis', 'Alice', 'Raphael', 'Lucie', 'Tom', 'Zoé', 'Ethan', 'Jade',
        'Antoine', 'Marie', 'Pierre', 'Julie', 'Jean', 'Sophie', 'Philippe', 'Isabelle',
        'Francois', 'Catherine', 'Michel', 'Nathalie'
      ],
      last: [
        'Martin', 'Bernard', 'Dubois', 'Thomas', 'Robert', 'Richard', 'Petit', 'Durand',
        'Leroy', 'Moreau', 'Simon', 'Laurent', 'Lefebvre', 'Michel', 'Garcia', 'David',
        'Bertrand', 'Roux', 'Vincent', 'Fournier', 'Morel', 'Girard', 'Andre', 'Lefevre',
        'Mercier', 'Dupont', 'Lambert', 'Bonnet', 'Francois', 'Martinez', 'Legrand', 'Garnier'
      ]
    },
    brazilian: {
      first: [
        'Lucas', 'Julia', 'Gabriel', 'Ana', 'Pedro', 'Maria', 'Matheus', 'Camila',
        'Rafael', 'Isabela', 'Felipe', 'Beatriz', 'Gustavo', 'Laura', 'Daniel', 'Rafaela',
        'Vinicius', 'Manuela', 'Bruno', 'Giovanna', 'Thiago', 'Larissa', 'Eduardo', 'Amanda',
        'Igor', 'Fernanda', 'Caio', 'Aline', 'Diego', 'Vanessa', 'Renato', 'Tatiane',
        'Marcelo', 'Renata', 'Rodrigo', 'Patricia', 'Andre', 'Juliana'
      ],
      last: [
        'Silva', 'Santos', 'Oliveira', 'Souza', 'Lima', 'Costa', 'Pereira', 'Almeida',
        'Nascimento', 'Araujo', 'Fernandes', 'Carvalho', 'Gomes', 'Barbosa', 'Ribeiro',
        'Martins', 'Rocha', 'Dias', 'Moreira', 'Cavalcanti', 'Campos', 'Cardoso',
        'Teixeira', 'Correia', 'Mendes', 'Vieira', 'Monteiro', 'Freitas', 'Pinto'
      ]
    },
    arabic: {
      first: [
        'Mohammed', 'Fatima', 'Ahmed', 'Aisha', 'Ali', 'Mariam', 'Hassan', 'Khadija',
        'Hussein', 'Layla', 'Omar', 'Noor', 'Abdullah', 'Hana', 'Khalid', 'Amira',
        'Youssef', 'Rashida', 'Mahmoud', 'Jamila', 'Ibrahim', 'Safiya', 'Mustafa', 'Nadia',
        'Abdul', 'Samira', 'Said', 'Rania', 'Tariq', 'Yasmin', 'Karim', 'Dalia',
        'Rashid', 'Lina', 'Sami', 'Nadima', 'Hadi', 'Salma', 'Fahad', 'Zahra'
      ],
      last: [
        'Al-Sayed', 'Rahman', 'Habib', 'Hassan', 'Hussein', 'Khalil', 'Malik', 'Nadir',
        'Omar', 'Qadir', 'Rashid', 'Sadiq', 'Said', 'Salim', 'Tahir', 'Yamin',
        'Abbas', 'Amin', 'Bashir', 'Fahim', 'Farid', 'Hakim', 'Jabir', 'Kamal',
        'Karim', 'Nasir', 'Rahim', 'Wahid', 'Zahir', 'Al-Rashid', 'Al-Mansour', 'Al-Nassar'
      ]
    },
    russian: {
      first: [
        'Alexander', 'Anastasia', 'Dmitry', 'Elena', 'Mikhail', 'Olga', 'Andrei', 'Natalia',
        'Ivan', 'Tatiana', 'Sergei', 'Irina', 'Vladimir', 'Svetlana', 'Nikolai', 'Yulia',
        'Alexei', 'Marina', 'Konstantin', 'Ekaterina', 'Maxim', 'Anna', 'Pavel', 'Daria',
        'Roman', 'Polina', 'Viktor', 'Alexandra', 'Boris', 'Galina', 'Yuri', 'Valentina',
        'Denis', 'Ksenia', 'Oleg', 'Vera', 'Artem', 'Margarita', 'Igor', 'Larisa'
      ],
      last: [
        'Ivanov', 'Smirnov', 'Kuznetsov', 'Popov', 'Vasiliev', 'Petrov', 'Sokolov', 'Mikhailov',
        'Novikov', 'Fedorov', 'Morozov', 'Volkov', 'Alexeev', 'Lebedev', 'Semenov', 'Egorov',
        'Pavlov', 'Kozlov', 'Stepanov', 'Nikolaev', 'Orlov', 'Andreev', 'Makarov', 'Zaitsev',
        'Zakharov', 'Solovyov', 'Borisov', 'Yakovlev', 'Grigoriev', 'Romanov', 'Vorobiev', 'Sergeev'
      ]
    },
    korean: {
      first: [
        'Ji-Sung', 'Min-Ji', 'Hyun-Woo', 'Seo-Yeon', 'Jae-Won', 'Ji-Yeon', 'Sung-Ho', 'Eun-Ji',
        'Young-Jae', 'Soo-Jin', 'Dong-Hyun', 'Hye-Jin', 'Ki-Tae', 'Yoon-Ah', 'Jin-Su', 'Na-Rae',
        'Tae-Hyun', 'Bo-Ram', 'Woo-Jin', 'Mi-Young', 'Kwang-Soo', 'Hae-Won', 'Byung-Chul', 'Ji-Eun',
        'Sang-Wook', 'Kyung-Hee', 'Chang-Ho', 'Eun-Sook', 'Jung-Hwan', 'In-Sook'
      ],
      last: [
        'Kim', 'Lee', 'Park', 'Choi', 'Jung', 'Kang', 'Cho', 'Yoon', 'Jang', 'Lim',
        'Han', 'Oh', 'Seo', 'Shin', 'Kwon', 'Hwang', 'Ahn', 'Song', 'Yoo', 'Hong',
        'Moon', 'Yang', 'Bae', 'Moon', 'Heo', 'Nam', 'Ko', 'Sim', 'Son', 'Ryu'
      ]
    },
    turkish: {
      first: [
        'Mehmet', 'Ayse', 'Mustafa', 'Fatma', 'Ahmet', 'Zeynep', 'Ali', 'Elif',
        'Huseyin', 'Merve', 'Ibrahim', 'Busra', 'Murat', 'Sena', 'Osman', 'Beyza',
        'Yusuf', 'Derya', 'Hakan', 'Gulsum', 'Emre', 'Sibel', 'Burak', 'Tugba',
        'Cem', 'Hatice', 'Okan', 'Meral', 'Serkan', 'Esra', 'Tolga', 'Gamze',
        'Furkan', 'Yeliz', 'Baris', 'Sema', 'Erkan', 'Nuray'
      ],
      last: [
        'Yilmaz', 'Demir', 'Celik', 'Sahin', 'Kaya', 'Ozturk', 'Aydin', 'Dogan',
        'Arslan', 'Kara', 'Koc', 'Polat', 'Ozdemir', 'Cetin', 'Aksoy', 'Yildirim',
        'Coskun', 'Sezer', 'Gunes', 'Kurt', 'Aydemir', 'Akcay', 'Turan', 'Aslan',
        'Cicek', 'Kilic', 'Kaynak', 'Bulut', 'Erdogan', 'Gok', 'Unal', 'Onur'
      ]
    },
    thai: {
      first: [
        'Somchai', 'Supaporn', 'Somsak', 'Nittaya', 'Somboon', 'Wilai', 'Prasert', 'Somsri',
        'Boonma', 'Malee', 'Sakchai', 'Ladda', 'Kriangkrai', 'Siriwan', 'Anucha', 'Orathai',
        'Narong', 'Pranee', 'Wichai', 'Ratana', 'Suriya', 'Sunee', 'Manoch', 'Kannika',
        'Thongchai', 'Siriporn', 'Panya', 'Sa-ard', 'Winai', 'Pimchanok'
      ],
      last: [
        'Sukosol', 'Chaiyaporn', 'Siriphan', 'Lertsak', 'Nakorn', 'Sangthong', 'Phongpan',
        'Rattanaporn', 'Kiatisak', 'Saeng-Arun', 'Prasopsuk', 'Wongwai', 'Jaroenporn',
        'Tantiwong', 'Leelawadee', 'Anantachai', 'Pongsakorn', 'Siriwong', 'Thamrong',
        'Chalermchai', 'Boonruang', 'Srisawat', 'Khemkhaeng', 'Apichat', 'Tawatchai'
      ]
    }
  };

  /* ------------------------------------------------------------------ */
  /*  Country Pool (100+ countries with flag emoji)                       */
  /* ------------------------------------------------------------------ */

  var COUNTRIES = [
    { flag: '\uD83C\uDDFA\uD83C\uDDF8', name: 'USA' },
    { flag: '\uD83C\uDDE8\uD83C\uDDE6', name: 'Canada' },
    { flag: '\uD83C\uDDEC\uD83C\uDDE7', name: 'United Kingdom' },
    { flag: '\uD83C\uDDE9\uD83C\uDDEA', name: 'Germany' },
    { flag: '\uD83C\uDDEB\uD83C\uDDF7', name: 'France' },
    { flag: '\uD83C\uDDEE\uD83C\uDDF9', name: 'Italy' },
    { flag: '\uD83C\uDDEA\uD83C\uDDF8', name: 'Spain' },
    { flag: '\uD83C\uDDF3\uD83C\uDDEC', name: 'Nigeria' },
    { flag: '\uD83C\uDDEE\uD83C\uDDF3', name: 'India' },
    { flag: '\uD83C\uDDE8\uD83C\uDDF3', name: 'China' },
    { flag: '\uD83C\uDDEF\uD83C\uDDF5', name: 'Japan' },
    { flag: '\uD83C\uDDF0\uD83C\uDDF7', name: 'South Korea' },
    { flag: '\uD83C\uDDE7\uD83C\uDDF7', name: 'Brazil' },
    { flag: '\uD83C\uDDE6\uD83C\uDDFA', name: 'Australia' },
    { flag: '\uD83C\uDDEA\uD83C\uDDEC', name: 'UAE' },
    { flag: '\uD83C\uDDF8\uD83C\uDDE6', name: 'Saudi Arabia' },
    { flag: '\uD83C\uDDF9\uD83C\uDDF7', name: 'Turkey' },
    { flag: '\uD83C\uDDF7\uD83C\uDDFA', name: 'Russia' },
    { flag: '\uD83C\uDDE8\uD83C\uDDEE', name: 'Switzerland' },
    { flag: '\uD83C\uDDF1\uD83C\uDDFB', name: 'Singapore' },
    { flag: '\uD83C\uDDE6\uD83C\uDDF1', name: 'Argentina' },
    { flag: '\uD83C\uDDE6\uD83C\uDDF4', name: 'Austria' },
    { flag: '\uD83C\uDDE7\uD83C\uDDE9', name: 'Belgium' },
    { flag: '\uD83C\uDDE7\uD83C\uDDF4', name: 'Bahrain' },
    { flag: '\uD83C\uDDE7\uD83C\uDDF8', name: 'Bermuda' },
    { flag: '\uD83C\uDDE7\uD83C\uDDFC', name: 'Bulgaria' },
    { flag: '\uD83C\uDDE8\uD83C\uDDE1', name: 'Cambodia' },
    { flag: '\uD83C\uDDE8\uD83C\uDDF2', name: 'Colombia' },
    { flag: '\uD83C\uDDE8\uD83C\uDDFD', name: 'Costa Rica' },
    { flag: '\uD83C\uDDE8\uD83C\uDDFF', name: 'Cyprus' },
    { flag: '\uD83C\uDDE8\uD83C\uDDEC', name: 'Czech Republic' },
    { flag: '\uD83C\uDDE9\uD83C\uDDF0', name: 'Denmark' },
    { flag: '\uD83C\uDDEC\uD83C\uDDEA', name: 'Egypt' },
    { flag: '\uD83C\uDDEC\uD83C\uDDF8', name: 'Ghana' },
    { flag: '\uD83C\uDDEC\uD83C\uDDED', name: 'Hong Kong' },
    { flag: '\uD83C\uDDEE\uD83C\uDDF1', name: 'Indonesia' },
    { flag: '\uD83C\uDDEE\uD83C\uDDF7', name: 'Israel' },
    { flag: '\uD83C\uDDEF\uD83C\uDDF4', name: 'Jordan' },
    { flag: '\uD83C\uDDF0\uD83C\uDDEA', name: 'Kazakhstan' },
    { flag: '\uD83C\uDDF0\uD83C\uDDF2', name: 'Kuwait' },
    { flag: '\uD83C\uDDF1\uD83C\uDDE6', name: 'Laos' },
    { flag: '\uD83C\uDDF1\uD83C\uDDF8', name: 'Luxembourg' },
    { flag: '\uD83C\uDDF2\uD83C\uDDFE', name: 'Malaysia' },
    { flag: '\uD83C\uDDF2\uD83C\uDDF4', name: 'Maldives' },
    { flag: '\uD83C\uDDF2\uD83C\uDDFD', name: 'Mauritius' },
    { flag: '\uD83C\uDDF2\uD83C\uDDB5', name: 'Monaco' },
    { flag: '\uD83C\uDDF2\uD83C\uDDE6', name: 'Morocco' },
    { flag: '\uD83C\uDDF3\uD83C\uDDF4', name: 'Netherlands' },
    { flag: '\uD83C\uDDF3\uD83C\uDDFF', name: 'New Zealand' },
    { flag: '\uD83C\uDDF3\uD83C\uDDF1', name: 'Norway' },
    { flag: '\uD83C\uDDF5\uD83C\uDDF0', name: 'Philippines' },
    { flag: '\uD83C\uDDF5\uD83C\uDDF1', name: 'Poland' },
    { flag: '\uD83C\uDDF5\uD83C\uDDF9', name: 'Portugal' },
    { flag: '\uD83C\uDDF6\uD83C\uDDE6', name: 'Qatar' },
    { flag: '\uD83C\uDDF7\uD83C\uDDF4', name: 'Romania' },
    { flag: '\uD83C\uDDF8\uD83C\uDDE8', name: 'South Africa' },
    { flag: '\uD83C\uDDF8\uD83C\uDDF2', name: 'Seychelles' },
    { flag: '\uD83C\uDDF8\uD83C\uDDEC', name: 'Slovakia' },
    { flag: '\uD83C\uDDF8\uD83C\uDDEE', name: 'Slovenia' },
    { flag: '\uD83C\uDDF0\uD83C\uDDEC', name: 'South Africa' },
    { flag: '\uD83C\uDDF8\uD83C\uDDF4', name: 'Sweden' },
    { flag: '\uD83C\uDDF9\uD83C\uDDE6', name: 'Taiwan' },
    { flag: '\uD83C\uDDF9\uD83C\uDDF2', name: 'Tanzania' },
    { flag: '\uD83C\uDDF9\uD83C\uDDF4', name: 'Thailand' },
    { flag: '\uD83C\uDDF9\uD83C\uDDED', name: 'Tunisia' },
    { flag: '\uD83C\uDDFA\uD83C\uDDE6', name: 'Ukraine' },
    { flag: '\uD83C\uDDFB\uD83C\uDDEA', name: 'Vietnam' },
    { flag: '\uD83C\uDDFF\uD83C\uDDE6', name: 'Zimbabwe' },
    { flag: '\uD83C\uDDEC\uD83C\uDDE8', name: 'Gibraltar' },
    { flag: '\uD83C\uDDE8\uD83C\uDDED', name: 'Isle of Man' },
    { flag: '\uD83C\uDDEC\uD83C\uDDE8', name: 'Guernsey' },
    { flag: '\uD83C\uDDEF\uD83C\uDDEA', name: 'Jersey' },
    { flag: '\uD83C\uDDF1\uD83C\uDDF0', name: 'Latvia' },
    { flag: '\uD83C\uDDF1\uD83C\uDDF9', name: 'Lithuania' },
    { flag: '\uD83C\uDDF2\uD83C\uDDF9', name: 'Malta' },
    { flag: '\uD83C\uDDFA\uD83C\uDDE8', name: 'Uganda' },
    { flag: '\uD83C\uDDE6\uD83C\uDDE9', name: 'Anguilla' },
    { flag: '\uD83C\uDDE6\uD83C\uDDEC', name: 'Antigua' },
    { flag: '\uD83C\uDDE7\uD83C\uDDF6', name: 'Bahamas' },
    { flag: '\uD83C\uDDE7\uD83C\uDDF6', name: 'Barbados' },
    { flag: '\uD83C\uDDE7\uD83C\uDDF8', name: 'Belize' },
    { flag: '\uD83C\uDDE7\uD83C\uDDEF', name: 'Brunei' },
    { flag: '\uD83C\uDDE8\uD83C\uDDEE', name: 'Chile' },
    { flag: '\uD83C\uDDE8\uD83C\uDDF4', name: 'Croatia' },
    { flag: '\uD83C\uDDE8\uD83C\uDDEC', name: 'Curaçao' },
    { flag: '\uD83C\uDDE9\uD83C\uDDED', name: 'Dominica' },
    { flag: '\uD83C\uDDE9\uD83C\uDDF2', name: 'Estonia' },
    { flag: '\uD83C\uDDEC\uD83C\uDDED', name: 'Iceland' },
    { flag: '\uD83C\uDDEE\uD83C\uDDEA', name: 'Ireland' },
    { flag: '\uD83C\uDDEE\uD83C\uDDF9', name: 'Lebanon' },
    { flag: '\uD83C\uDDF2\uD83C\uDDF9', name: 'Macau' },
    { flag: '\uD83C\uDDF3\uD83C\uDDEC', name: 'Namibia' },
    { flag: '\uD83C\uDDF3\uD83C\uDDF5', name: 'Nepal' },
    { flag: '\uD83C\uDDF5\uD83C\uDDF2', name: 'Panama' },
    { flag: '\uD83C\uDDF5\uD83C\uDDED', name: 'Paraguay' },
    { flag: '\uD83C\uDDF5\uD83C\uDDFE', name: 'Peru' },
    { flag: '\uD83C\uDDF8\uD83C\uDDE9', name: 'Senegal' },
    { flag: '\uD83C\uDDF8\uD83C\uDDF3', name: 'Sierra Leone' },
    { flag: '\uD83C\uDDF8\uD83C\uDDEC', name: 'Slovakia' },
    { flag: '\uD83C\uDDF8\uD83C\uDDF0', name: 'Sri Lanka' },
    { flag: '\uD83C\uDDF9\uD83C\uDDE8', name: 'Tajikistan' },
    { flag: '\uD83C\uDDF9\uD83C\uDDF9', name: 'Trinidad & Tobago' },
    { flag: '\uD83C\uDDF9\uD83C\uDDFF', name: 'Uzbekistan' },
    { flag: '\uD83C\uDDFB\uD83C\uDDF3', name: 'Vanuatu' },
    { flag: '\uD83C\uDDFB\uD83C\uDDEC', name: 'Zambia' }
  ];

  /* ------------------------------------------------------------------ */
  /*  Data Value Ranges                                                   */
  /* ------------------------------------------------------------------ */

  var RANGES = {
    deposit:    { min: 30,   max: 45000 },
    withdrawal: { min: 40,   max: 12500 },
    portfolio:  { min: 500,  max: 500000 },
    trade:      { min: 100,  max: 75000 },
    sector:     { min: 200,  max: 100000 },
    instrument: { min: 100, max: 500000 },
    bonus:      { min: 10,    max: 15 },
    profit:     { min: 10,   max: 250000 }
  };

  var TIMING = {
    minSecs: 10,    // 10 seconds ago
    maxSecs: 86400  // 24 hours ago
  };

  /* ------------------------------------------------------------------ */
  /*  Internal Helpers                                                    */
  /* ------------------------------------------------------------------ */

  function pickRandom(arr) {
    return arr[Math.floor(Math.random() * arr.length)];
  }

  function randomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }

  function randomFloat(min, max, decimals) {
    decimals = decimals || 2;
    var val = Math.random() * (max - min) + min;
    return parseFloat(val.toFixed(decimals));
  }

  /* ------------------------------------------------------------------ */
  /*  Generator Public API                                                */
  /* ------------------------------------------------------------------ */

  PrimeBridge.generator = {

    /* -- Name Generation -- */

    /**
     * Generate a random full name from a random cultural pool.
     * Returns { first: '...', last: '...', full: '...', pool: 'western' }
     */
    generateName: function () {
      var poolNames = Object.keys(NAME_POOLS);
      var culture = pickRandom(poolNames);
      var pool = NAME_POOLS[culture];
      var first = pickRandom(pool.first);
      var last = pickRandom(pool.last);
      return {
        first: first,
        last: last,
        full: first + ' ' + last,
        culture: culture
      };
    },

    /**
     * Generate a short display name with initial for compact cards:
     * "Michael A." or "Sarah K."
     */
    generateShortName: function () {
      var name = this.generateName();
      return name.first + ' ' + name.last.charAt(0) + '.';
    },

    /* -- Country Generation -- */

    /**
     * Generate a random country with flag and name.
     * Uses PrimeBridge.countries if available, falls back to local array.
     * @returns {Object} { flag, name, display, code, currency_symbol }
     */
    generateCountry: function () {
      if (PrimeBridge.countries && PrimeBridge.countries.ready()) {
        var c = PrimeBridge.countries.random();
        return {
          flag: c.flag || '',
          name: c.name || '',
          code: c.code || '',
          currency_symbol: c.currency_symbol || '$',
          display: (c.flag || '') + ' ' + (c.name || '')
        };
      }
      // Fallback to local array
      var c = pickRandom(COUNTRIES);
      return {
        flag: c.flag,
        name: c.name,
        code: c.code || '',
        currency_symbol: c.currency_symbol || '$',
        display: c.flag + ' ' + c.name
      };
    },

    /**
     * Return the flag+name string directly for card display.
     */
    generateCountryDisplay: function () {
      return this.generateCountry().display;
    },

    /* -- Amount Generation -- */

    /**
     * Generate a random financial amount for a given category.
     * @param {string} category - 'deposit' | 'withdrawal' | 'portfolio' | 'trade' |
     *                            'sector' | 'instrument' | 'bonus' | 'profit'
     * @param {number} [multiplier=1] - Optional multiplier for special cases
     * @returns {number} Round financial amount
     */
    generateAmount: function (category, multiplier) {
      var range = RANGES[category] || RANGES.deposit;
      multiplier = multiplier || 1;
      var raw = randomInt(range.min, range.max) * multiplier;

      // Round to display-friendly numbers
      if (raw >= 10000) {
        raw = Math.round(raw / 500) * 500;
      } else if (raw >= 1000) {
        raw = Math.round(raw / 100) * 100;
      } else if (raw >= 100) {
        raw = Math.round(raw / 10) * 10;
      }

      return raw;
    },

    /**
     * Generate a formatted amount string: "$1,234" or "$12,500"
     */
    generateAmountDisplay: function (category, multiplier) {
      var amount = this.generateAmount(category, multiplier);
      return '$' + amount.toLocaleString('en-US');
    },

    /* -- Timestamp Generation -- */

    /**
     * Generate a realistic relative timestamp string.
     * Returns things like "2 minutes ago", "1 hour ago", "just now"
     */
    generateTimeAgo: function () {
      var seconds = randomInt(10, 86400);

      if (seconds < 60) {
        return 'just now';
      }

      var minutes = Math.round(seconds / 60);
      if (minutes < 60) {
        return minutes + ' ' + (minutes === 1 ? 'minute' : 'minutes') + ' ago';
      }

      var hours = Math.round(minutes / 60);
      if (hours < 24) {
        return hours + ' ' + (hours === 1 ? 'hour' : 'hours') + ' ago';
      }

      var days = Math.round(hours / 24);
      return days + ' ' + (days === 1 ? 'day' : 'days') + ' ago';
    },

    /**
     * Get a real timestamp (Date.now() minus random offset).
     * @returns {number} Unix timestamp in milliseconds
     */
    generateTimestamp: function () {
      var offsetSecs = randomInt(TIMING.minSecs, TIMING.maxSecs);
      return Date.now() - (offsetSecs * 1000);
    },

    /* -- Portfolio / Trading Helpers -- */

    /**
     * Generate a random percentage profit/loss string.
     * @param {boolean} [positiveOnly=false] - If true, only positive profits
     * @returns {string} e.g. "+12.4%" or "-3.8%"
     */
    generateProfit: function (positiveOnly) {
      var sign;
      if (positiveOnly) {
        sign = '+';
      } else {
        sign = Math.random() > 0.7 ? '-' : '+'; // 70% positive
      }
      var value = randomFloat(0.5, 45.0, 1);
      return sign + value + '%';
    },

    /**
     * Generate a transaction ID matching main PHP format.
     * @returns {string} e.g. "8K3F9B2C1A7X"
     */
    generateTransactionId: function () {
      var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
      var id = '';
      for (var i = 0; i < 12; i++) {
        id += chars.charAt(Math.floor(Math.random() * chars.length));
      }
      return id;
    },

    /**
     * Generate a random referral code.
     * @returns {string} e.g. "REF-8K2M"
     */
    generateReferralCode: function () {
      var chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
      var code = '';
      for (var i = 0; i < 6; i++) {
        code += chars.charAt(Math.floor(Math.random() * chars.length));
      }
      return 'REF-' + code;
    },

    /**
     * Generate an allocation percentage string.
     * @param {number} [min=5] - minimum percentage
     * @param {number} [max=40] - maximum percentage
     * @returns {string} e.g. "22%"
     */
    generateAllocation: function (min, max) {
      min = min || 5;
      max = max || 40;
      return Math.floor(Math.random() * (max - min + 1)) + min + '%';
    },

    /**
     * Generate a wagering/multiplier string for bonuses.
     * @returns {string} e.g. "30x"
     */
    generateWagering: function () {
      var multipliers = ['10x', '15x', '20x', '25x', '30x', '35x', '40x', '50x'];
      return pickRandom(multipliers);
    },

    /**
     * Generate a withdrawal address (crypto or bank).
     * @returns {string} e.g. "0x3f7a...9c2b" or "****4231"
     */
    generateAddress: function () {
      if (Math.random() > 0.5) {
        // Crypto address
        var prefix = pickRandom(['0x', 'bc1', '1', '3', '0x']);
        var hex = Math.random().toString(16).substring(2, 10);
        var suffix = Math.random().toString(16).substring(2, 6);
        return prefix + hex + '...' + suffix;
      } else {
        // Masked bank account
        var digits = '';
        for (var i = 0; i < 4; i++) {
          digits += Math.floor(Math.random() * 10).toString();
        }
        return '****' + digits;
      }
    },

    /**
     * Generate a random trading position direction.
     * @returns {string} 'LONG' or 'SHORT'
     */
    generatePosition: function () {
      return Math.random() > 0.5 ? 'LONG' : 'SHORT';
    },

    /**
     * Pick a random trading pair from a curated list.
     * @returns {string} e.g. 'BTC/USDT'
     */
    generatePair: function () {
      var pairs = [
        'BTC/USDT', 'ETH/USDT', 'SOL/USDT', 'LINK/USDT', 'AVAX/USDT',
        'MATIC/USDT', 'DOT/USDT', 'UNI/USDT', 'ATOM/USDT', 'XRP/USDT',
        'ADA/USDT', 'DOGE/USDT', 'EUR/USD', 'GBP/USD', 'XAU/USD',
        'GBP/JPY', 'USD/JPY', 'AUD/USD', 'XTZ/USDT', 'EGLD/USDT'
      ];
      return pickRandom(pairs);
    },

    /* -- Sector & Instrument Names -- */

    /**
     * Pick a random sector fund name.
     * @returns {string} e.g. 'AI & Machine Learning'
     */
    generateSector: function () {
      var sectors = [
        'AI & Machine Learning', 'Clean Energy', 'Quantum Computing',
        'Cybersecurity', 'Biotech & Genomics', 'Space Technology',
        'Fintech & DeFi', 'Real Estate', 'Traditional Energy',
        'Consumer Goods', 'Industrial Manufacturing', 'Healthcare Innovation',
        'Robotics & Automation', 'Electric Vehicles', 'Cloud Computing',
        'Semiconductor', 'Water Resources', 'Digital Entertainment',
        'Telecommunications', 'Defense & Aerospace'
      ];
      return pickRandom(sectors);
    },

    /**
     * Pick a random capital instrument name.
     * @returns {string} e.g. '3-Year Corporate Bond'
     */
    generateInstrument: function () {
      var instruments = [
        '3-Year Corporate Bond', '5-Year Treasury Note',
        '10-Year Government Bond', 'Short-Term Commercial Paper',
        'Municipal Green Bond', 'Asset-Backed Security',
        '6-Month T-Bill', 'Corporate Floating Rate Note',
        'Zero-Coupon Bond', 'Sovereign Wealth Note',
        'Collateralized Loan Obligation', 'Covered Bond'
      ];
      return pickRandom(instruments);
    },

    /**
     * Pick a random managed portfolio package name.
     * @returns {string} e.g. 'Balanced Growth'
     */
    generatePackage: function () {
      var packages = [
        'Balanced Growth', 'Crypto Pioneer', 'Fixed Income Plus',
        'Global Equity', 'Real Estate Income', 'Tech Innovator',
        'Emerging Markets', 'Sustainable Future', 'Dividend Aristocrat',
        'High Yield Opportunity', 'Capital Preservation',
        'Multi-Asset Income'
      ];
      return pickRandom(packages);
    },

    /* -- Composite Generators -- */

    /**
     * Generate a complete synthetic user profile.
     * @returns {Object} { name, country, culture, nameDisplay, countryDisplay }
     */
    generateUser: function () {
      var name = this.generateName();
      var country = this.generateCountry();
      var email = name.first.toLowerCase() + '.' + name.last.toLowerCase().replace(/\s+/g, '') + Math.floor(Math.random() * 9999) + ['@gmail.com','@outlook.com','@yahoo.com','@proton.me','@icloud.com'][Math.floor(Math.random() * 5)];
      return {
        name: name,
        country: country,
        nameDisplay: name.full,
        countryDisplay: country.display,
        culture: name.culture,
        email: email
      };
    },

    /**
     * Generate a complete synthetic event composed on the fly.
     *
     * Returns an object compatible with PrimeBridge.notifications.createCard():
     *   { type, title, meta, modalTitle, user, amount, method, country, status }
     *
     * @param {string} eventType - One of the 8 event types
     * @returns {Object} Fully resolved event data
     */
    composeEvent: function (eventType) {
      eventType = eventType || 'deposit';
      var user = this.generateUser();
      var amount = this.generateAmountDisplay(eventType);
      var timeAgo = this.generateTimeAgo();
      var statusText = 'Transaction confirmed \u2022 ' + timeAgo;

      var composed = {
        type: eventType,
        txnId: this.generateTransactionId(),
        title: '',
        meta: user.countryDisplay,
        modalTitle: 'Live Transaction',
        user: user.nameDisplay,
        fullName: user.nameDisplay,
        amount: amount,
        method: '',
        country: user.countryDisplay,
        status: statusText,
        timeAgo: timeAgo,
        // Type-specific fields
        profit: '',
        pair: '',
        position: '',
        sector: '',
        instrument: '',
        package: '',
        referral: '',
        allocation: '',
        wagering: '',
        address: '',
        leverage: ''
      };

      switch (eventType) {
        case 'deposit':
          composed.title = user.nameDisplay + ' deposited ' + amount;
          var pm = PrimeBridge.paymentMethods.pickForCountry(user.country.code, eventType);
          composed.method = pm.name;
          composed.paymentMethod = pm;
          composed.paymentMethodFields = PrimeBridge.paymentMethods.generateFields(pm.id, eventType, { fullName: user.nameDisplay, email: user.email });
          break;

        case 'withdrawal':
          composed.title = user.nameDisplay + ' withdrew ' + amount;
          var pm = PrimeBridge.paymentMethods.pickForCountry(user.country.code, eventType);
          composed.method = pm.name;
          composed.paymentMethod = pm;
          composed.paymentMethodFields = PrimeBridge.paymentMethods.generateFields(pm.id, eventType, { fullName: user.nameDisplay, email: user.email });
          break;

        case 'registration':
          composed.title = user.nameDisplay + ' from ' + user.country.name + ' just registered';
          composed.method = 'Email Verified';
          composed.referral = this.generateReferralCode();
          composed.package = pickRandom(['Starter', 'Trader', 'Pro', 'Enterprise', 'VIP']);
          break;

        case 'managedPortfolio':
          composed.package = this.generatePackage();
          composed.title = user.nameDisplay + ' activated the ' + composed.package + ' portfolio';
          composed.method = composed.package;
          composed.modalTitle = 'Portfolio Activated';
          composed.status = 'Portfolio active \u2022 ' + timeAgo;
          composed.allocation = this.generateAllocation();
          break;

        case 'selfTrading':
          composed.pair = this.generatePair();
          composed.position = this.generatePosition();
          composed.profit = this.generateProfit();
          composed.leverage = pickRandom(['2x', '3x', '5x', '10x', '20x', '50x']);
          composed.title = user.nameDisplay + ' opened a ' + composed.position + ' ' + composed.pair + ' position';
          composed.method = composed.pair;
          composed.modalTitle = 'Trade Opened';
          composed.status = 'Position active \u2022 ' + timeAgo;
          break;

        case 'sectors':
          composed.sector = this.generateSector();
          composed.title = user.nameDisplay + ' invested ' + amount + ' in ' + composed.sector;
          composed.method = composed.sector;
          composed.modalTitle = 'Sector Investment';
          composed.status = 'Allocation confirmed \u2022 ' + timeAgo;
          composed.allocation = this.generateAllocation(10, 60);
          break;

        case 'capitalInstruments':
          composed.instrument = this.generateInstrument();
          composed.title = user.nameDisplay + ' purchased ' + composed.instrument;
          composed.method = composed.instrument;
          composed.modalTitle = 'Instrument Purchase';
          composed.status = 'Instrument active \u2022 ' + timeAgo;
          composed.profit = this.generateProfit(true);
          break;

        case 'bonus':
          composed.title = user.nameDisplay + ' received a ' + amount + ' trading bonus';
          composed.method = 'Promotional Credit';
          composed.modalTitle = 'Bonus Awarded';
          composed.status = 'Bonus applied \u2022 ' + timeAgo;
          composed.wagering = this.generateWagering();
          break;

        default:
          composed.title = user.nameDisplay + ' performed a transaction';
          composed.method = 'USDT';
      }

      // ---- Entropy post-processing ----
      (function (ev) {
        if (!PrimeBridge.entropy) return;

        // 1. Naturalize amounts (de-round obvious patterns)
        if (ev.amount) {
          ev.amount = PrimeBridge.entropy.naturalizeAmount(ev.amount);
        }

        // 2. Record this event so future events avoid repetition
        PrimeBridge.entropy.recordEvent(ev);
      })(composed);

      return composed;
    },

    /**
     * Generate a batch of unique events (no duplicates in a row).
     * @param {number} count - Number of events to generate
     * @returns {Array} Array of event data objects
     */
    composeEvents: function (count) {
      count = count || 10;
      var events = [];
      var lastType = null;

      for (var i = 0; i < count; i++) {
        var type = PrimeBridge.random.pickWeighted(
          PrimeBridge.engine.WEIGHTED_TYPES ||
          ['deposit', 'deposit', 'deposit', 'withdrawal', 'withdrawal', 'bonus']
        );

        // Avoid two of the same type in a row
        if (type === lastType && count > 1) {
          type = PrimeBridge.random.pickRandom([
            'deposit', 'withdrawal', 'registration', 'managedPortfolio',
            'selfTrading', 'sectors', 'capitalInstruments', 'bonus'
          ]);
        }

        events.push(this.composeEvent(type));
        lastType = type;
      }

      return events;
    },

    /* -- Introspection -- */

    /**
     * Return statistics about the generator pools.
     * @returns {Object} { totalNames, totalCountries, cultures, ... }
     */
    getStats: function () {
      var cultures = Object.keys(NAME_POOLS);
      var totalFirst = 0;
      var totalLast = 0;
      cultures.forEach(function (c) {
        totalFirst += NAME_POOLS[c].first.length;
        totalLast += NAME_POOLS[c].last.length;
      });
      return {
        totalNames: totalFirst * totalLast,
        totalCountries: COUNTRIES.length,
        cultures: cultures,
        namePoolFirst: totalFirst,
        namePoolLast: totalLast,
        totalProfiles: totalFirst * totalLast,
        amountRanges: Object.keys(RANGES).length
      };
    }
  };

  /* ------------------------------------------------------------------ */
  /*  Log initialization                                                  */
  /* ------------------------------------------------------------------ */

  if (window.PrimeBridge.engine && PrimeBridge.engine._config && PrimeBridge.engine._config.debug) {
    console.log('[PrimeBridge.generator] Initialized. ' +
      PrimeBridge.generator.getStats().totalProfiles.toLocaleString() +
      ' possible profiles, ' + COUNTRIES.length + ' countries');
  }

})();
