import { ThemedText } from "@/components/themed-text";
import { ThemedView } from "@/components/themed-view";
import { LiveScoreMatch } from "@/types/api";
import React from "react";
import { useTranslation } from "react-i18next";
import { StyleSheet, View } from "react-native";
import Svg, { Circle, G } from "react-native-svg";
interface TennisStatsCardProps {
match: LiveScoreMatch;
isDark: boolean;
}
// Helper for Circular Progress
// Updated to match screenshot: Labels on top, circle in middle, values on sides.
const CircularStat = ({
value1,
value2,
label,
color1 = "#2196F3", // Blue
color2 = "#FFC107", // Gold
size = 50,
strokeWidth = 5,
isDark,
}: {
value1: string; // "67%" or "67"
value2: string;
label: string;
color1?: string;
color2?: string;
size?: number;
strokeWidth?: number;
isDark: boolean;
}) => {
const parse = (v: string) => parseFloat(v.replace("%", "")) || 0;
const v1 = parse(value1);
const v2 = parse(value2);
// Radius
const r = (size - strokeWidth) / 2;
const c = size / 2;
const circumference = 2 * Math.PI * r;
// Inner radius
const innerR = r - strokeWidth - 2; // small gap
const innerCircumference = 2 * Math.PI * innerR;
// Colors for text need to be readable on white background if card is always white
// Screenshot shows white card on dark background.
// BUT the text "First Serve %" is dark/grey.
// The values 67.4 are Blue/Gold.
// The circle tracks are light grey maybe.
const trackColor = isDark ? "#333" : "#E0E0E0";
const labelColor = isDark ? "#AAA" : "#666";
return (
{/* Label centered */}
{label}
{/* Left Value P1 */}
{value1}
{/* Circle Graphic */}
{/* Right Value P2 */}
{value2}
);
};
// Helper for Bar Stat
const BarStat = ({
label,
value1,
value2,
color1 = "#2196F3",
color2 = "#FFC107",
isDark,
}: {
label: string;
value1: string;
value2: string;
color1?: string;
color2?: string;
isDark: boolean;
}) => {
// Parse to number for bars
const v1 = parseFloat(value1) || 0;
const v2 = parseFloat(value2) || 0;
const total = v1 + v2 || 1;
const p1 = (v1 / total) * 100;
const p2 = (v2 / total) * 100;
return (
{value1}
{label}
{value2}
);
};
export function TennisStatsCard({ match, isDark }: TennisStatsCardProps) {
const { t } = useTranslation();
const statistics = match.statistics;
if (!statistics || !Array.isArray(statistics) || statistics.length === 0) {
return null;
}
// Check structure. If it's the Football type (home/away keys), we shouldn't be here (LiveDetail logic checks sport).
// But safely handle:
const isTennisFormat =
"player_key" in statistics[0] || "name" in statistics[0];
if (!isTennisFormat) return null;
// Group by name
// Map Name -> { p1Value: string, p2Value: string }
const statsMap: Record =
{};
// Assume P1 is first_player_key
// Using home_team_key as fallback/primary since first_player_key isn't in type definition
// In many APIs, for tennis, home_team_key === first_player_key
const p1Key = match.home_team_key;
// In generic response, keys might be strings vs numbers.
// Let's rely on finding two entries for same "name" and "period".
// Or just iterate.
(statistics as any[]).forEach((stat) => {
// Filter for 'match' period (total)
if (stat.period !== "match") return;
const name = stat.name;
if (!statsMap[name]) statsMap[name] = { p1: "0", p2: "0", type: stat.type };
// Assign to P1 or P2
// If we know p1Key
if (p1Key && stat.player_key == p1Key) {
statsMap[name].p1 = stat.value;
} else {
statsMap[name].p2 = stat.value;
}
});
// Define intended stats to show
// Top (Circles):
// "1st serve percentage" (1st Serve %)
// "1st serve points won" (1st Serve Win %)
// "Break Points Converted" -> "Break Success %" (Screenshot: 破发成功率)
// Or match keys exactly: "1st serve percentage", "1st serve points won", "Break Points Converted"
// Middle (Bars):
// "Aces" (Screenshot: 发球得分? Or implies Aces).
// "Double Faults" (Screenshot: 双误)
// "Service Points Won"
const circleStats = [
{ key: "1st serve percentage", label: t("detail.stats.first_serve") },
{
key: "1st serve points won",
label: t("detail.stats.first_serve_points"),
},
{ key: "Break Points Converted", label: t("detail.stats.break_points") },
];
const barStats = [
{ key: "Aces", label: t("detail.stats.aces") },
{ key: "Double Faults", label: t("detail.stats.double_faults") },
];
// Check if any of the target stats actually exist in the map
const hasAnyStat = [...circleStats, ...barStats].some((s) => statsMap[s.key]);
if (!hasAnyStat) return null;
return (
{t("detail.statistics")}
{circleStats.map((s) =>
statsMap[s.key] ? (
) : null,
)}
{barStats.map((s) =>
statsMap[s.key] ? (
) : null,
)}
);
}
const styles = StyleSheet.create({
container: {
margin: 16,
padding: 16,
borderRadius: 12,
},
title: {
fontSize: 16,
fontWeight: "bold",
marginBottom: 20,
},
circlesRow: {
flexDirection: "row",
justifyContent: "space-around",
marginBottom: 24,
},
circularStatContainer: {
alignItems: "center",
width: "30%",
},
circularLabel: {
fontSize: 12,
textAlign: "center",
opacity: 0.7,
height: 32, // Fixed height for alignment
},
circularRow: {
flexDirection: "row",
alignItems: "center",
},
statValueSide: {
fontSize: 12,
fontWeight: "bold",
},
statValue: {
fontSize: 12,
fontWeight: "600",
},
barsColumn: {
gap: 16,
},
barStatContainer: {
marginBottom: 8,
},
barHeader: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 8,
},
pill: {
paddingHorizontal: 10,
paddingVertical: 4,
borderRadius: 12,
minWidth: 40,
alignItems: "center",
},
pillText: {
color: "white",
fontWeight: "bold",
fontSize: 12,
},
barLabel: {
opacity: 0.8,
},
barTrack: {
flexDirection: "row",
height: 6,
backgroundColor: "#333",
borderRadius: 3,
overflow: "hidden",
},
barFill: {
height: "100%",
},
});