import { Client } from "pg"; import bcrypt from "bcryptjs"; import { config } from "dotenv"; config(); // load .env const DATABASE_URL = process.env.DATABASE_URL!; const DEFAULT_RULES = { GK: { GOAL: 10, ASSIST: 3, YELLOW_CARD: -1, RED_CARD: -3, SECOND_YELLOW: -3, CLEAN_SHEET: 6, PENALTY_SAVED: 5, PENALTY_MISSED: -2, OWN_GOAL: -2, MOTM: 3, EXTRA_TIME_BONUS: 1, INJURY_NO_SUB: -1 }, DEF: { GOAL: 8, ASSIST: 3, YELLOW_CARD: -1, RED_CARD: -3, SECOND_YELLOW: -3, CLEAN_SHEET: 4, PENALTY_SAVED: 0, PENALTY_MISSED: -2, OWN_GOAL: -2, MOTM: 3, EXTRA_TIME_BONUS: 1, INJURY_NO_SUB: -1 }, MID: { GOAL: 5, ASSIST: 3, YELLOW_CARD: -2, RED_CARD: -3, SECOND_YELLOW: -3, CLEAN_SHEET: 1, PENALTY_SAVED: 0, PENALTY_MISSED: -2, OWN_GOAL: -2, MOTM: 3, EXTRA_TIME_BONUS: 1, INJURY_NO_SUB: -1 }, FWD: { GOAL: 4, ASSIST: 3, YELLOW_CARD: -1, RED_CARD: -3, SECOND_YELLOW: -3, CLEAN_SHEET: 0, PENALTY_SAVED: 0, PENALTY_MISSED: -2, OWN_GOAL: -2, MOTM: 3, EXTRA_TIME_BONUS: 1, INJURY_NO_SUB: -1 }, }; const COUNTRY_FORMATIONS: Record = { BRA:"4-3-3",FRA:"4-3-3",ARG:"4-3-3",ENG:"4-3-3",ESP:"4-3-3",GER:"4-2-3-1",POR:"4-3-3",NED:"4-3-3", BEL:"4-3-3",CRO:"4-3-3",MAR:"4-3-3",IRN:"4-5-1",URU:"4-3-3",SEN:"4-3-3",KOR:"4-3-3",JPN:"4-3-3", MEX:"4-3-3",USA:"4-3-3",CAN:"4-3-3",AUS:"4-3-3",POL:"4-3-3",DEN:"4-3-3",SUI:"4-2-3-1",SRB:"3-4-3", WAL:"5-3-2",TUN:"4-3-3",CMR:"4-3-3",GHA:"4-2-3-1",ECU:"4-3-3",QAT:"5-3-2",KSA:"4-3-3",CRC:"5-4-1", }; const COUNTRIES = [ {name:"برزیل",code:"BRA",flag:"🇧🇷",group:"G"},{name:"سربیا",code:"SRB",flag:"🇷🇸",group:"G"}, {name:"سوئیس",code:"SUI",flag:"🇨🇭",group:"G"},{name:"کامرون",code:"CMR",flag:"🇨🇲",group:"G"}, {name:"فرانسه",code:"FRA",flag:"🇫🇷",group:"D"},{name:"استرالیا",code:"AUS",flag:"🇦🇺",group:"D"}, {name:"دانمارک",code:"DEN",flag:"🇩🇰",group:"D"},{name:"تونس",code:"TUN",flag:"🇹🇳",group:"D"}, {name:"آرژانتین",code:"ARG",flag:"🇦🇷",group:"C"},{name:"عربستان",code:"KSA",flag:"🇸🇦",group:"C"}, {name:"مکزیک",code:"MEX",flag:"🇲🇽",group:"C"},{name:"لهستان",code:"POL",flag:"🇵🇱",group:"C"}, {name:"ایران",code:"IRN",flag:"🇮🇷",group:"B"},{name:"انگلیس",code:"ENG",flag:"🏴󠁧󠁢󠁥󠁮󠁧󠁿",group:"B"}, {name:"آمریکا",code:"USA",flag:"🇺🇸",group:"B"},{name:"ولز",code:"WAL",flag:"🏴󠁧󠁢󠁷󠁬󠁳󠁿",group:"B"}, {name:"آلمان",code:"GER",flag:"🇩🇪",group:"E"},{name:"ژاپن",code:"JPN",flag:"🇯🇵",group:"E"}, {name:"اسپانیا",code:"ESP",flag:"🇪🇸",group:"E"},{name:"کاستاریکا",code:"CRC",flag:"🇨🇷",group:"E"}, {name:"بلژیک",code:"BEL",flag:"🇧🇪",group:"F"},{name:"کانادا",code:"CAN",flag:"🇨🇦",group:"F"}, {name:"مراکش",code:"MAR",flag:"🇲🇦",group:"F"},{name:"کرواسی",code:"CRO",flag:"🇭🇷",group:"F"}, {name:"پرتغال",code:"POR",flag:"🇵🇹",group:"H"},{name:"غنا",code:"GHA",flag:"🇬🇭",group:"H"}, {name:"اروگوئه",code:"URU",flag:"🇺🇾",group:"H"},{name:"کره جنوبی",code:"KOR",flag:"🇰🇷",group:"H"}, {name:"هلند",code:"NED",flag:"🇳🇱",group:"A"},{name:"سنگال",code:"SEN",flag:"🇸🇳",group:"A"}, {name:"اکوادور",code:"ECU",flag:"🇪🇨",group:"A"},{name:"قطر",code:"QAT",flag:"🇶🇦",group:"A"}, ]; const PLAYERS_DATA = [ {name:"آلیسون بکر",pos:"GK",code:"BRA",price:6.0,pts:42},{name:"تیاگو سیلوا",pos:"DEF",code:"BRA",price:6.5,pts:38}, {name:"مارکینیوس",pos:"DEF",code:"BRA",price:6.0,pts:35},{name:"کاسمیرو",pos:"MID",code:"BRA",price:8.0,pts:52}, {name:"نیمار",pos:"FWD",code:"BRA",price:11.5,pts:68},{name:"وینیسیوس جونیور",pos:"FWD",code:"BRA",price:10.5,pts:72}, {name:"ریچارلیسون",pos:"FWD",code:"BRA",price:8.5,pts:55},{name:"هوگو لوریس",pos:"GK",code:"FRA",price:6.0,pts:40}, {name:"رافائل واران",pos:"DEF",code:"FRA",price:6.5,pts:36},{name:"کیلیان امباپه",pos:"FWD",code:"FRA",price:12.5,pts:88}, {name:"آنتوان گریزمان",pos:"MID",code:"FRA",price:9.5,pts:62},{name:"اولیویه ژیرو",pos:"FWD",code:"FRA",price:7.5,pts:48}, {name:"اوسمان دمبله",pos:"FWD",code:"FRA",price:8.0,pts:44},{name:"امیلیانو مارتینز",pos:"GK",code:"ARG",price:6.5,pts:55}, {name:"لیونل مسی",pos:"FWD",code:"ARG",price:12.5,pts:92},{name:"خولیان آلوارز",pos:"FWD",code:"ARG",price:8.5,pts:60}, {name:"رودریگو دپاول",pos:"MID",code:"ARG",price:7.5,pts:45},{name:"نیکولاس اوتامندی",pos:"DEF",code:"ARG",price:5.5,pts:32}, {name:"جوردن پیکفورد",pos:"GK",code:"ENG",price:5.5,pts:38},{name:"جود بلینگهام",pos:"MID",code:"ENG",price:10.5,pts:75}, {name:"هری کین",pos:"FWD",code:"ENG",price:11.0,pts:70},{name:"بوکایو ساکا",pos:"MID",code:"ENG",price:8.5,pts:58}, {name:"فیل فودن",pos:"MID",code:"ENG",price:9.0,pts:62},{name:"جان استونز",pos:"DEF",code:"ENG",price:6.0,pts:34}, {name:"اونای سیمون",pos:"GK",code:"ESP",price:5.5,pts:36},{name:"پدری",pos:"MID",code:"ESP",price:9.0,pts:60}, {name:"گاوی",pos:"MID",code:"ESP",price:8.5,pts:55},{name:"آلوارو موراتا",pos:"FWD",code:"ESP",price:7.5,pts:46}, {name:"دنی اولمو",pos:"MID",code:"ESP",price:7.0,pts:42},{name:"مانوئل نویر",pos:"GK",code:"GER",price:6.0,pts:38}, {name:"توماس مولر",pos:"MID",code:"GER",price:8.0,pts:50},{name:"کای هاورتز",pos:"MID",code:"GER",price:8.5,pts:52}, {name:"یامله موسیالا",pos:"MID",code:"GER",price:9.0,pts:65},{name:"آنتونیو رودیگر",pos:"DEF",code:"GER",price:5.5,pts:30}, {name:"دیوگو کوستا",pos:"GK",code:"POR",price:5.5,pts:35},{name:"کریستیانو رونالدو",pos:"FWD",code:"POR",price:11.0,pts:65}, {name:"برونو فرناندز",pos:"MID",code:"POR",price:10.0,pts:70},{name:"رافائل لئائو",pos:"FWD",code:"POR",price:8.5,pts:55}, {name:"روبن دیاز",pos:"DEF",code:"POR",price:6.0,pts:36},{name:"علیرضا بیرانوند",pos:"GK",code:"IRN",price:5.0,pts:28}, {name:"مهدی طارمی",pos:"FWD",code:"IRN",price:8.0,pts:50},{name:"سردار آزمون",pos:"FWD",code:"IRN",price:7.5,pts:44}, {name:"علی کریمی",pos:"MID",code:"IRN",price:6.0,pts:32},{name:"رامین رضاییان",pos:"DEF",code:"IRN",price:5.0,pts:22}, {name:"یاسین بونو",pos:"GK",code:"MAR",price:6.5,pts:58},{name:"اشرف حکیمی",pos:"DEF",code:"MAR",price:8.0,pts:62}, {name:"حکیم زیاش",pos:"MID",code:"MAR",price:7.5,pts:48},{name:"یوسف النصیری",pos:"FWD",code:"MAR",price:7.0,pts:45}, {name:"دومینیک لیواکوویچ",pos:"GK",code:"CRO",price:6.0,pts:50},{name:"لوکا مودریچ",pos:"MID",code:"CRO",price:9.5,pts:68}, {name:"ایوان پریشیچ",pos:"MID",code:"CRO",price:7.5,pts:48},{name:"آندره کراماریچ",pos:"FWD",code:"CRO",price:7.0,pts:44}, {name:"آندریس نوپرت",pos:"GK",code:"NED",price:5.5,pts:36},{name:"ویرخیل فان دایک",pos:"DEF",code:"NED",price:7.0,pts:48}, {name:"دنزل دامفریس",pos:"DEF",code:"NED",price:7.5,pts:52},{name:"کودی گاکپو",pos:"FWD",code:"NED",price:8.0,pts:58}, {name:"تیبو کورتوا",pos:"GK",code:"BEL",price:6.5,pts:44},{name:"کوین دبروینه",pos:"MID",code:"BEL",price:11.0,pts:72}, {name:"رومله لوکاکو",pos:"FWD",code:"BEL",price:9.5,pts:55}, ]; function cuid() { return 'c' + Math.random().toString(36).slice(2, 11) + Date.now().toString(36); } async function main() { const client = new Client({ connectionString: DATABASE_URL }); await client.connect(); console.log("✅ Connected to database"); // ─── پاک کردن همه داده‌ها ──────────────────────────── console.log("🗑️ Clearing all data..."); await client.query(` TRUNCATE TABLE "Payment", "TeamPlayer", "Team", "Session", "MatchLineup", "MatchEvent", "PlayerMatchStat", "ScoringRule", "Match", "Player", "Country", "Group", "Round", "Gameweek", "Package", "User" RESTART IDENTITY CASCADE `); console.log("✅ Cleared"); // ─── ادمین ──────────────────────────────────────────── console.log("👤 Creating users..."); const adminPwd = await bcrypt.hash("admin123", 10); const userPwd = await bcrypt.hash("user123", 10); await client.query(` INSERT INTO "User" (id, email, name, password, role, "createdAt") VALUES ($1, 'admin@worldcup.com', 'ادمین', $2, 'ADMIN', NOW()), ($3, 'ali@test.com', 'علی احمدی', $4, 'USER', NOW()), ($5, 'sara@test.com', 'سارا رضایی', $4, 'USER', NOW()), ($6, 'reza@test.com', 'رضا محمدی', $4, 'USER', NOW()) `, [cuid(), adminPwd, cuid(), userPwd, cuid(), cuid()]); // ─── گروه‌ها ────────────────────────────────────────── console.log("🏟️ Creating groups..."); const groupMap: Record = {}; for (const name of ["A","B","C","D","E","F","G","H"]) { const id = cuid(); await client.query(`INSERT INTO "Group" (id, name) VALUES ($1, $2)`, [id, name]); groupMap[name] = id; } // ─── تیم‌های ملی ───────────────────────────────────── console.log("🌍 Creating countries..."); const countryMap: Record = {}; for (const c of COUNTRIES) { const id = cuid(); const formation = COUNTRY_FORMATIONS[c.code] ?? "4-3-3"; await client.query( `INSERT INTO "Country" (id, name, code, "flagUrl", "groupId", "defaultFormation") VALUES ($1,$2,$3,$4,$5,$6)`, [id, c.name, c.code, c.flag, groupMap[c.group], formation] ); countryMap[c.code] = id; } // ─── بازیکنان ───────────────────────────────────────── console.log("⚽ Creating players..."); for (const p of PLAYERS_DATA) { const countryId = countryMap[p.code]; if (!countryId) continue; await client.query( `INSERT INTO "Player" (id, name, position, "countryId", price, "totalPoints", "isActive", "createdAt", "updatedAt") VALUES ($1,$2,$3,$4,$5,$6,true,NOW(),NOW())`, [cuid(), p.name, p.pos, countryId, p.price, p.pts] ); } // ─── قوانین امتیازدهی ──────────────────────────────── console.log("📊 Creating scoring rules..."); for (const [pos, rules] of Object.entries(DEFAULT_RULES)) { for (const [eventType, points] of Object.entries(rules)) { await client.query( `INSERT INTO "ScoringRule" (id, position, "eventType", points, "updatedAt") VALUES ($1,$2,$3,$4,NOW())`, [cuid(), pos, eventType, points] ); } } // ─── دورها ──────────────────────────────────────────── console.log("🔄 Creating rounds..."); const rounds: Record = {}; const roundsData = [ {num:1, name:"دور اول - مرحله گروهی", active:true, deadline:"2026-06-15T10:00:00Z"}, {num:2, name:"دور دوم - مرحله گروهی", active:false, deadline:"2026-06-22T10:00:00Z"}, {num:3, name:"دور سوم - مرحله گروهی", active:false, deadline:"2026-06-29T10:00:00Z"}, {num:4, name:"دور چهارم - یک‌هشتم نهایی",active:false, deadline:"2026-07-05T10:00:00Z"}, ]; for (const r of roundsData) { const id = cuid(); await client.query( `INSERT INTO "Round" (id, number, name, "isActive", deadline, "createdAt") VALUES ($1,$2,$3,$4,$5,NOW())`, [id, r.num, r.name, r.active, r.deadline] ); rounds[r.num] = id; } // ─── بازی‌ها ────────────────────────────────────────── console.log("🏆 Creating matches..."); const matchesData = [ {home:"QAT",away:"ECU",hS:0, aS:2, st:"FINISHED", date:"2026-06-20T16:00:00Z",r:1}, {home:"ENG",away:"IRN",hS:6, aS:2, st:"FINISHED", date:"2026-06-21T13:00:00Z",r:1}, {home:"ARG",away:"KSA",hS:1, aS:2, st:"FINISHED", date:"2026-06-22T10:00:00Z",r:1}, {home:"FRA",away:"AUS",hS:4, aS:1, st:"FINISHED", date:"2026-06-22T19:00:00Z",r:1}, {home:"GER",away:"JPN",hS:1, aS:2, st:"FINISHED", date:"2026-06-23T13:00:00Z",r:1}, {home:"ESP",away:"CRC",hS:7, aS:0, st:"FINISHED", date:"2026-06-23T19:00:00Z",r:1}, {home:"BEL",away:"CAN",hS:1, aS:0, st:"FINISHED", date:"2026-06-23T16:00:00Z",r:1}, {home:"BRA",away:"SRB",hS:2, aS:0, st:"FINISHED", date:"2026-06-24T19:00:00Z",r:1}, {home:"POR",away:"GHA",hS:3, aS:2, st:"FINISHED", date:"2026-06-24T16:00:00Z",r:1}, {home:"MAR",away:"CRO",hS:0, aS:0, st:"FINISHED", date:"2026-06-23T10:00:00Z",r:1}, {home:"NED",away:"SEN",hS:2, aS:0, st:"FINISHED", date:"2026-06-21T16:00:00Z",r:1}, {home:"IRN",away:"WAL",hS:2, aS:0, st:"FINISHED", date:"2026-06-25T13:00:00Z",r:2}, {home:"FRA",away:"DEN",hS:2, aS:1, st:"FINISHED", date:"2026-06-26T19:00:00Z",r:2}, {home:"ARG",away:"MEX",hS:2, aS:0, st:"FINISHED", date:"2026-06-26T22:00:00Z",r:2}, {home:"BRA",away:"SUI",hS:1, aS:0, st:"FINISHED", date:"2026-06-28T19:00:00Z",r:2}, {home:"ENG",away:"USA",hS:0, aS:0, st:"FINISHED", date:"2026-06-25T19:00:00Z",r:2}, {home:"BRA",away:"CMR",hS:1, aS:0, st:"SCHEDULED", date:"2026-07-02T19:00:00Z",r:3}, {home:"FRA",away:"TUN",hS:null,aS:null,st:"SCHEDULED",date:"2026-07-01T16:00:00Z",r:3}, {home:"NED",away:"ARG",hS:2, aS:2, st:"FINISHED", date:"2026-12-09T19:00:00Z",r:4,stage:"ROUND_OF_16"}, {home:"FRA",away:"ENG",hS:2, aS:1, st:"FINISHED", date:"2026-12-10T19:00:00Z",r:4,stage:"ROUND_OF_16"}, {home:"ARG",away:"FRA",hS:3, aS:3, st:"FINISHED", date:"2026-12-18T15:00:00Z",r:4,stage:"FINAL"}, ]; for (const m of matchesData) { const homeId = countryMap[m.home], awayId = countryMap[m.away]; if (!homeId || !awayId) continue; await client.query( `INSERT INTO "Match" (id,"homeTeamId","awayTeamId","homeScore","awayScore",status,stage,"matchDate","roundId","createdAt") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,NOW())`, [cuid(), homeId, awayId, m.hS ?? null, m.aS ?? null, m.st, (m as any).stage ?? "GROUP", m.date, rounds[m.r]] ); } // ─── پکیج‌ها ────────────────────────────────────────── console.log("📦 Creating packages..."); for (const pkg of [ {name:"پکیج نقره‌ای", budgetBonus:10, price:50000, desc:"۱۰ میلیون به بودجه اضافه کن"}, {name:"پکیج طلایی", budgetBonus:20, price:90000, desc:"۲۰ میلیون به بودجه اضافه کن"}, {name:"پکیج الماس", budgetBonus:30, price:120000,desc:"۳۰ میلیون به بودجه اضافه کن"}, ]) { await client.query( `INSERT INTO "Package" (id, name, "budgetBonus", price, description, "isActive") VALUES ($1,$2,$3,$4,$5,true)`, [cuid(), pkg.name, pkg.budgetBonus, pkg.price, pkg.desc] ); } await client.end(); console.log("\n✅ Seed done!"); console.log(" admin@worldcup.com / admin123"); console.log(" ali@test.com / user123"); } main().catch(e => { console.error("❌", e); process.exit(1); });