// Same Odds Statistics Section (สถิติอัตราต่อรองในอดีตเดียวกัน)
// Uses fixture_analysis_odds_api table (unified API)
let sameOddsData = null;
let sameOddsApiData = null; // Data from fixture_analysis_odds_api table (unified)
let sameOddsLeagueName = null; // League name from thscore_fixture_analyses table
let currentOddsType = 2; // 1=1x2, 2=Asian Handicap, 3=Over/Under
function getSameOdds(fixtureId, homeTeamName, awayTeamName) {
// Single API call for unified odds data (สถิติอัตราต่อรองในอดีตเดียวกัน only)
getData('fixtures/' + fixtureId + '/analysis/odds-stats', null, (response) => {
if (response?.oddsApi) {
sameOddsApiData = response.oddsApi;
}
if (response?.leagueName) {
sameOddsLeagueName = response.leagueName;
}
// Calculate and render สถิติอัตราต่อรองในอดีตเดียวกัน section
calculateSameOddsStats(homeTeamName, awayTeamName);
renderSameOdds();
});
}
function calculateSameOddsStats(homeTeamName, awayTeamName) {
// Uses fixture_analysis_odds_api table data (unified API)
// H2H data is NOT a valid fallback - it's a completely different data source
if (sameOddsApiData) {
calculateSameOddsStatsFromApiData(homeTeamName, awayTeamName);
return;
}
// No same odds data available - hide the section
sameOddsData = null;
}
// Calculate stats from fixture_analysis_odds_api table (unified API)
// Data format: ah_all_sum/up/draw/down, ah_main_sum/up/draw/down, ah_same_sum/up/draw/down (same for ou, op)
function calculateSameOddsStatsFromApiData(homeTeamName, awayTeamName) {
const d = sameOddsApiData;
console.log('[SameOdds] API Data:', d);
// Helper to calculate percentage
const pct = (val, sum) => sum > 0 ? Math.round((val / sum) * 100) : 0;
// Build categories from unified API (all, main, same) for each odds type
// Each category becomes a column in the chart
const buildCategories = (prefix) => {
const categories = [];
// "รวม" (All) column
const allSum = d[`${prefix}_all_sum`] || 0;
if (allSum > 0) {
categories.push({
home: pct(d[`${prefix}_all_up`] || 0, allSum),
draw: pct(d[`${prefix}_all_draw`] || 0, allSum),
away: pct(d[`${prefix}_all_down`] || 0, allSum),
category: `รวม (${allSum})`
});
}
// "ลีกหลัก" (Main league) column
const mainSum = d[`${prefix}_main_sum`] || 0;
if (mainSum > 0) {
categories.push({
home: pct(d[`${prefix}_main_up`] || 0, mainSum),
draw: pct(d[`${prefix}_main_draw`] || 0, mainSum),
away: pct(d[`${prefix}_main_down`] || 0, mainSum),
category: `ลีกหลัก (${mainSum})`
});
}
// "ลีกเดียวกัน" (Same league) column - use actual league name if available
const sameSum = d[`${prefix}_same_sum`] || 0;
if (sameSum > 0) {
const leagueLabel = sameOddsLeagueName || 'ลีกเดียวกัน';
categories.push({
home: pct(d[`${prefix}_same_up`] || 0, sameSum),
draw: pct(d[`${prefix}_same_draw`] || 0, sameSum),
away: pct(d[`${prefix}_same_down`] || 0, sameSum),
category: `${leagueLabel} (${sameSum})`
});
}
return categories;
};
// Build odds display from API values
const getOddsDisplay = () => {
return {
handicap: {
home: d.ah_up_odds || '-',
odds: d.ah_draw_odds || '-',
away: d.ah_down_odds || '-'
},
oneXTwo: {
home: d.op_up_odds || '-',
draw: d.op_draw_odds || '-',
away: d.op_down_odds || '-'
},
overUnder: {
over: d.ou_up_odds || '-',
odds: d.ou_draw_odds || '-',
under: d.ou_down_odds || '-'
}
};
};
const currentOdds = getOddsDisplay();
console.log('[SameOdds] currentOdds:', currentOdds);
sameOddsData = {
homeTeam: homeTeamName,
awayTeam: awayTeamName,
currentOdds: currentOdds,
// stats is array of columns from unified API (all, main, same)
stats: {
handicap: buildCategories('ah'),
oneXTwo: buildCategories('op'),
overUnder: buildCategories('ou')
},
labels: {
handicap: { home: 'เหย้าชนะ', draw: 'เสมอ', away: 'เยือนชนะ' },
oneXTwo: { home: 'เหย้าชนะ', draw: 'เสมอ', away: 'เยือนชนะ' },
overUnder: { home: 'สูง', draw: 'เสมอ', away: 'ต่ำ' }
}
};
console.log('[SameOdds] sameOddsData.stats:', sameOddsData.stats);
}
function renderSameOdds() {
if (!sameOddsData) return;
const data = sameOddsData;
const typeKey = currentOddsType === 1 ? 'oneXTwo' : (currentOddsType === 2 ? 'handicap' : 'overUnder');
const columns = data.stats[typeKey]; // Array of columns from database
const labels = data.labels[typeKey];
console.log(`[SameOdds RENDER] currentOddsType=${currentOddsType}, typeKey=${typeKey}`);
console.log(`[SameOdds RENDER] columns:`, columns);
const odds = currentOddsType === 1 ? data.currentOdds.oneXTwo :
(currentOddsType === 2 ? data.currentOdds.handicap : data.currentOdds.overUnder);
let html = `
`;
// Header row with team names
html += `
`;
html += `
`;
html += `
${data.homeTeam}
`;
html += `
`;
html += `
สถิติอัตราต่อรองในอดีตเดียวกัน
`;
html += `
`;
html += `
${data.awayTeam}
`;
html += `
`;
html += ``;
html += ``;
html += `
`;
// Content
html += `
`;
// Tab options
html += `
`;
html += `
`;
html += `
แฮนดิแคปเอเชีย
`;
html += `
1x2
`;
html += `
สูง/ต่ำ
`;
html += `
`;
html += `
`;
// Current odds display
html += `
`;
if (currentOddsType === 2) {
html += `แฮนดิแคปเอเชีย: ${odds.home}${odds.odds}${odds.away}`;
} else if (currentOddsType === 1) {
html += `1x2: ${odds.home}${odds.draw}${odds.away}`;
} else {
html += `สูง/ต่ำ: ${odds.over}${odds.odds}${odds.under}`;
}
html += `
`;
// Vertical bars - draw each column from database
html += `
`;
// Loop through all columns from database
for (const col of columns) {
html += renderSameOddsVoteBar(col, col.category, labels, currentOddsType);
}
html += `
`;
// Legend - always show all 3 (database gives what we need)
html += `
`;
html += `${labels.home}`;
html += `${labels.draw}`;
html += `${labels.away}`;
html += `(ข้อมูลข้างต้นมีไว้เพื่อการอ้างอิงเท่านั้น โดยอิงจากข้อมูลในอดีต)`;
html += `
`;
html += `
`; // fx-vote-data
html += `
`; // same-odds-section
$('#sameOddsSection').html(html);
}
function renderSameOddsVoteBar(stats, label, labels, oddsType) {
// Helper to get bar height - use pixel for 0%, percentage for others
const getBarHeight = (val) => val === 0 ? '2px' : `${Math.max(val, 5)}%`;
let html = `
`;
html += `
`;
// Home bar
html += `
`;
html += `
`;
html += `${stats.home}%`;
html += `
`;
html += `
`;
// Draw bar - always draw (database gives what we need)
html += `
`;
html += `
`;
html += `${stats.draw}%`;
html += `
`;
html += `
`;
// Away bar
html += `
`;
html += `
`;
html += `${stats.away}%`;
html += `
`;
html += `
`;
html += `
`;
html += `
${label}
`;
html += `
`;
return html;
}
function switchSameOddsBar(type) {
currentOddsType = type;
renderSameOdds();
}
// ============================================================================
// Odds Statistics Section (สถิติราคาต่อรอง)
// Uses H2H API data (fixture_analysis_h2hs table with odds)
// Calculates per-team stats from historical match results
// ============================================================================
let oddsStatsData = null;
let oddsStatsH2hData = null; // Store H2H data for recalculation
function getOddsStats(fixtureId, homeTeamName, awayTeamName) {
console.log('[OddsStats] getOddsStats called with fixtureId:', fixtureId);
// Fetch from H2H API - contains per-team historical match results with odds
getData('fixtures/' + fixtureId + '/analysis/h2h', null, (response) => {
console.log('[OddsStats] H2H API response:', response);
if (response?.home?.length > 0 || response?.away?.length > 0) {
oddsStatsH2hData = response;
calculateOddsStatsFromH2hData(response, homeTeamName, awayTeamName);
} else {
console.log('[OddsStats] No H2H data - hiding section');
$('#oddsStatsSection').html('');
}
}, (error) => {
console.log('[OddsStats] API error:', error);
$('#oddsStatsSection').html('');
});
}
// Calculate stats from H2H API data (fixture_analysis_h2hs with odds)
// Data structure: home/away arrays with matches, each match has odds array
// odds[0] = 1x2 (result_open: W/D/L), odds[1] = AH (result_open: W/D/L), odds[2] = O/U (result_open: O/D/U)
// odds[3] = 1x2 half, odds[4] = AH half, odds[5] = O/U half
function calculateOddsStatsFromH2hData(data, homeTeamName, awayTeamName) {
if (!data) {
$('#oddsStatsSection').html('');
return;
}
// Get checkbox states for filtering
const isHalfTime = $('#oddsStatHTSel').is(':checked');
const isOriginalHA = $('#oddsStatHASel').is(':checked');
// Offset for half time (0=full time, 3=half time)
const s = isHalfTime ? 3 : 0;
// Helper to calculate stats from matches array
const calcTeamStats = (matches, teamName, isHomeTeam) => {
if (!matches || matches.length === 0) {
return null;
}
// Filter matches if "ทีมเหย้า - ทีมเยือน เดิม" is checked
let filteredMatches = matches;
if (isOriginalHA) {
filteredMatches = matches.filter(m =>
isHomeTeam ? m.team_home === teamName : m.team_away === teamName
);
}
// Take up to 21 matches (like thscore)
const maxMatches = Math.min(21, filteredMatches.length);
const selectedMatches = filteredMatches.slice(0, maxMatches);
// Count AH results (from odds[s+1])
let ahWin = 0, ahDraw = 0, ahLose = 0, ahTotal = 0;
// Count O/U results (from odds[s+2])
let ouOver = 0, ouDraw = 0, ouUnder = 0, ouTotal = 0;
for (const match of selectedMatches) {
if (!match.odds) continue;
// AH result (index s+1)
const ahOdds = match.odds[s + 1];
if (ahOdds && ahOdds.result_open) {
ahTotal++;
if (ahOdds.result_open === 'W') ahWin++;
else if (ahOdds.result_open === 'D') ahDraw++;
else if (ahOdds.result_open === 'L') ahLose++;
}
// O/U result (index s+2)
const ouOdds = match.odds[s + 2];
if (ouOdds && ouOdds.result_open) {
ouTotal++;
if (ouOdds.result_open === 'O') ouOver++;
else if (ouOdds.result_open === 'D') ouDraw++;
else if (ouOdds.result_open === 'U') ouUnder++;
}
}
// Calculate percentages
const pct = (val, total) => total > 0 ? Math.round((val / total) * 100) : 0;
return {
games: ahTotal,
handicap: {
win: pct(ahWin, ahTotal),
draw: pct(ahDraw, ahTotal),
lose: pct(ahLose, ahTotal)
},
overUnder: {
games: ouTotal,
over: pct(ouOver, ouTotal),
draw: pct(ouDraw, ouTotal),
under: pct(ouUnder, ouTotal)
}
};
};
// Calculate stats for home team (from 'home' array) and away team (from 'away' array)
const homeStats = calcTeamStats(data.home, homeTeamName, true);
const awayStats = calcTeamStats(data.away, awayTeamName, false);
console.log('[OddsStats] Calculated stats:', { homeStats, awayStats });
if (!homeStats && !awayStats) {
$('#oddsStatsSection').html('');
return;
}
oddsStatsData = {
homeTeam: homeTeamName,
awayTeam: awayTeamName,
stats: {
handicap: {
homeGames: homeStats?.games || 0,
awayGames: awayStats?.games || 0,
home: homeStats?.handicap || { win: 0, draw: 0, lose: 0 },
away: awayStats?.handicap || { win: 0, draw: 0, lose: 0 }
},
overUnder: {
homeGames: homeStats?.overUnder?.games || 0,
awayGames: awayStats?.overUnder?.games || 0,
home: homeStats?.overUnder || { over: 0, draw: 0, under: 0 },
away: awayStats?.overUnder || { over: 0, draw: 0, under: 0 }
}
}
};
console.log('[OddsStats] Final data:', oddsStatsData);
renderOddsStats();
}
function renderOddsStats() {
if (!oddsStatsData) return;
// Get checkbox states
const isHalfTime = $('#oddsStatHTSel').is(':checked');
const isOriginalHA = $('#oddsStatHASel').is(':checked');
// Use the stats from oddsStatsData (calculated dynamically with checkbox filters)
const stats = oddsStatsData.stats;
const data = oddsStatsData;
let html = `
`;
// Header row with team names
html += `
`;
html += `
`;
html += `
${data.homeTeam}
`;
html += `
`;
html += `
สถิติราคาต่อรอง
`;
html += `
`;
html += `
${data.awayTeam}
`;
html += `
`;
html += ``;
html += ``;
html += `
`;
// Content
html += `
`;
// Checkbox options (preserve checked state)
html += `
`;
html += ``;
html += ``;
html += ``;
html += ``;
html += `
`;
// Helper to get bar height - use 2px for 0%, percentage for others
const getBarHeight = (val) => val === 0 ? '2px' : `${Math.max(val, 5)}%`;
// Y-Bar groups using fx-tb-a structure (Asian Handicap and Over/Under side by side)
html += `
`;
// Asian Handicap group - 3 categories (Win/Draw/Lose), each with home/away pair
html += `
`;
html += `ทีมเหย้า`;
html += `ทีมเยือน`;
html += `
`;
html += `
`; // fx-vote-data
html += `
`; // same-odds-section
$('#oddsStatsSection').html(html);
}
function switchOddsStat() {
// Recalculate from H2H data with new checkbox states
if (oddsStatsH2hData && oddsStatsData) {
calculateOddsStatsFromH2hData(oddsStatsH2hData, oddsStatsData.homeTeam, oddsStatsData.awayTeam);
}
}
// ============================================================================
// League Goal Difference Statistics Section (สถิติผลต่างประตูของลีก)
// Uses fixture_analysis_goal_diffs API data
// ============================================================================
let goalDiffData = null;
let goalDiffRawData = null;
function getGoalDiffStats(fixtureId, homeTeamName, awayTeamName) {
// Fetch goal diff data from API
getData('fixtures/' + fixtureId + '/analysis/goal/diff', null, (data) => {
if (!data || !data.goalDiff || data.goalDiff.length === 0) {
// No API data, will fall back to H2H calculation later
return;
}
goalDiffRawData = data.goalDiff;
processGoalDiffData(homeTeamName, awayTeamName);
}, () => {
// API fetch failed, will use H2H fallback
});
}
function processGoalDiffData(homeTeamName, awayTeamName) {
if (!goalDiffRawData) return;
// Find home and away data
const homeData = goalDiffRawData.find(d => d.team === 'home');
const awayData = goalDiffRawData.find(d => d.team === 'away');
if (!homeData && !awayData) return;
// Parse count values from database (stored as strings)
const parseCount = (val) => parseInt(val) || 0;
// Calculate max count for bar height scaling
const homeTotal = homeData ? (parseCount(homeData.win_2_plus) + parseCount(homeData.win_1) + parseCount(homeData.draw) + parseCount(homeData.lose_1) + parseCount(homeData.lose_2_plus)) : 0;
const awayTotal = awayData ? (parseCount(awayData.win_2_plus) + parseCount(awayData.win_1) + parseCount(awayData.draw) + parseCount(awayData.lose_1) + parseCount(awayData.lose_2_plus)) : 0;
const maxTotal = Math.max(homeTotal, awayTotal, 1);
goalDiffData = {
homeTeam: homeTeamName,
awayTeam: awayTeamName,
maxTotal: maxTotal,
categories: [
{
label: 'ชนะ 2 ลูกขึ้นไป',
home: homeData ? parseCount(homeData.win_2_plus) : 0,
away: awayData ? parseCount(awayData.win_2_plus) : 0
},
{
label: 'ชนะ 1 ลูก',
home: homeData ? parseCount(homeData.win_1) : 0,
away: awayData ? parseCount(awayData.win_1) : 0
},
{
label: 'เสมอ',
home: homeData ? parseCount(homeData.draw) : 0,
away: awayData ? parseCount(awayData.draw) : 0
},
{
label: 'แพ้ 1 ลูก',
home: homeData ? parseCount(homeData.lose_1) : 0,
away: awayData ? parseCount(awayData.lose_1) : 0
},
{
label: 'แพ้ 2 ลูกขึ้นไป',
home: homeData ? parseCount(homeData.lose_2_plus) : 0,
away: awayData ? parseCount(awayData.lose_2_plus) : 0
}
]
};
renderGoalDiffStats();
}
function renderGoalDiffStats() {
if (!goalDiffData) return;
const data = goalDiffData;
let html = `
`;
// Header row with team names
html += `
`;
html += `
`;
html += `
${data.homeTeam}
`;
html += `
`;
html += `
สถิติผลต่างประตูของลีก
`;
html += `
`;
html += `
${data.awayTeam}
`;
html += `
`;
html += ``;
html += ``;
html += `
`;
// Content
html += `
`;
// Vertical bars for goal difference categories
html += `
`;
for (const cat of data.categories) {
html += renderGoalDiffVoteBar(cat, data.maxTotal);
}
html += `
`;
// Legend
html += `
`;
html += `ทีมเหย้า`;
html += `ทีมเยือน`;
html += `
`;
html += `
`; // fx-vote-data
html += `
`; // same-odds-section
$('#goalDiffSection').html(html);
}
function renderGoalDiffVoteBar(cat, maxTotal) {
// Helper to get bar height - scale based on max total count
const getBarHeight = (val) => {
if (val === 0) return '2px';
const pct = Math.round((val / maxTotal) * 100);
return `${Math.max(pct, 5)}%`;
};
let html = `
`;
html += `
`;
// Home bar (orange) - show count, not percentage
html += `
`;
html += `
`;
html += `${cat.home}`;
html += `
`;
html += `
`;
// Away bar (purple) - show count, not percentage
html += `