/**
 * @license
 * Copyright 2025 Qwen
 * SPDX-License-Identifier: Apache-2.0
 */

import type React from 'react';
import { Box, Text } from 'ink';
import { theme } from '../../semantic-colors.js';
import type {
  ContextCategoryBreakdown,
  ContextToolDetail,
  ContextMemoryDetail,
  ContextSkillDetail,
} from '../../types.js';
import { t } from '../../../i18n/index.js';

// Progress bar characters
const FILLED = '\u2588'; // █ - filled block
const BUFFER = '\u2592'; // ▒ - medium shade (autocompact buffer)
const EMPTY = '\u2591'; // ░ - light shade (free space)

const CONTENT_WIDTH = 56;

interface ContextUsageProps {
  modelName: string;
  totalTokens: number;
  contextWindowSize: number;
  breakdown: ContextCategoryBreakdown;
  builtinTools: ContextToolDetail[];
  mcpTools: ContextToolDetail[];
  memoryFiles: ContextMemoryDetail[];
  skills: ContextSkillDetail[];
  /** True when totalTokens is estimated (no API call yet) */
  isEstimated?: boolean;
  /** When true, show per-item detail breakdowns. Default: false (compact). */
  showDetails?: boolean;
}

/**
 * Truncate a string to maxLen, appending '…' if truncated.
 */
function truncateName(name: string, maxLen: number): string {
  if (name.length <= maxLen) return name;
  return name.slice(0, maxLen - 1) + '\u2026';
}

/**
 * Format token count for display (e.g. 1234 -> "1.2k", 123456 -> "123.5k")
 */
function formatTokens(tokens: number): string {
  if (tokens >= 1000) {
    return `${(tokens / 1000).toFixed(1)}k`;
  }
  return `${tokens}`;
}

/**
 * Render a three-segment progress bar: used | autocompact buffer | free space.
 */
const ProgressBar: React.FC<{
  usedPercentage: number;
  bufferPercentage: number;
  width: number;
}> = ({ usedPercentage, bufferPercentage, width }) => {
  const usedCount = Math.round((Math.min(usedPercentage, 100) / 100) * width);
  const bufferCount = Math.round(
    (Math.min(bufferPercentage, 100 - usedPercentage) / 100) * width,
  );
  const freeCount = Math.max(0, width - usedCount - bufferCount);

  const usedStr = FILLED.repeat(Math.max(0, usedCount));
  const freeStr = EMPTY.repeat(Math.max(0, freeCount));
  const bufferStr = BUFFER.repeat(Math.max(0, bufferCount));

  // Used color: accent by default, warning/error at high usage.
  let usedColor = theme.text.accent;
  if (usedPercentage > 80) {
    usedColor = theme.status.error;
  } else if (usedPercentage > 60) {
    usedColor = theme.status.warning;
  }

  return (
    <Text>
      <Text color={usedColor}>{usedStr}</Text>
      <Text color={theme.text.secondary}>{freeStr}</Text>
      <Text color={theme.status.warning}>{bufferStr}</Text>
    </Text>
  );
};

/**
 * A row showing a category with its token count and percentage.
 */
const CategoryRow: React.FC<{
  symbol: string;
  label: string;
  tokens: number;
  contextWindowSize: number;
  symbolColor?: string;
}> = ({ symbol, label, tokens, contextWindowSize, symbolColor }) => {
  const percentage = ((tokens / contextWindowSize) * 100).toFixed(1);
  const tokenStr = `${formatTokens(tokens)} ${t('tokens')} (${percentage}%)`;

  return (
    <Box width={CONTENT_WIDTH}>
      <Box width={2}>
        <Text color={symbolColor || theme.text.secondary}>{symbol}</Text>
      </Box>
      <Box width={24}>
        <Text color={theme.text.primary}>{label}</Text>
      </Box>
      <Box flexGrow={1} justifyContent="flex-end">
        <Text color={theme.text.secondary}>{tokenStr}</Text>
      </Box>
    </Box>
  );
};

/**
 * A detail row for individual items (MCP tools, memory files, skills).
 */
const DETAIL_NAME_MAX_LEN = 30;

const DetailRow: React.FC<{
  name: string;
  tokens: number;
}> = ({ name, tokens }) => {
  const tokenStr =
    tokens > 0 ? `${formatTokens(tokens)} ${t('tokens')}` : `0 ${t('tokens')}`;
  return (
    <Box width={CONTENT_WIDTH} paddingLeft={2}>
      <Text color={theme.text.secondary}>{'\u2514'} </Text>
      <Box width={32}>
        <Text color={theme.text.link}>
          {truncateName(name, DETAIL_NAME_MAX_LEN)}
        </Text>
      </Box>
      <Box flexGrow={1} justifyContent="flex-end">
        <Text color={theme.text.secondary}>{tokenStr}</Text>
      </Box>
    </Box>
  );
};

export const ContextUsage: React.FC<ContextUsageProps> = ({
  modelName,
  totalTokens,
  contextWindowSize,
  breakdown,
  builtinTools,
  mcpTools,
  memoryFiles,
  skills,
  isEstimated,
  showDetails = false,
}) => {
  const percentage =
    contextWindowSize > 0 ? (totalTokens / contextWindowSize) * 100 : 0;

  // Sort detail items by token count (descending) for better readability
  const sortedBuiltinTools = [...builtinTools].sort(
    (a, b) => b.tokens - a.tokens,
  );
  const sortedMcpTools = [...mcpTools].sort((a, b) => b.tokens - a.tokens);
  const sortedMemoryFiles = [...memoryFiles].sort(
    (a, b) => b.tokens - a.tokens,
  );
  // Sort skills: loaded first, then by total token cost descending
  const sortedSkills = [...skills].sort((a, b) => {
    if (a.loaded !== b.loaded) return a.loaded ? -1 : 1;
    const aTotal = a.tokens + (a.bodyTokens ?? 0);
    const bTotal = b.tokens + (b.bodyTokens ?? 0);
    return bTotal - aTotal;
  });

  return (
    <Box
      borderStyle="round"
      borderColor={theme.border.default}
      flexDirection="column"
      paddingY={1}
      paddingX={2}
    >
      {/* Title */}
      <Text bold color={theme.text.accent}>
        {t('Context Usage')}
      </Text>
      <Box height={1} />

      {isEstimated ? (
        <>
          {/* No API data yet — show hint instead of progress bar */}
          <Box marginBottom={1}>
            <Text color={theme.status.warning} italic>
              {t('No API response yet. Send a message to see actual usage.')}
            </Text>
          </Box>

          {/* Estimated overhead categories */}
          <Text bold color={theme.text.primary}>
            {t('Estimated pre-conversation overhead')}
          </Text>
          <Text color={theme.text.secondary}>
            {t('Model')}: {modelName}
            {'  '}
            {t('Context window')}: {formatTokens(contextWindowSize)}{' '}
            {t('tokens')}
          </Text>
          <Box height={1} />
        </>
      ) : (
        <>
          {/* Model name + context window info */}
          <Box width={CONTENT_WIDTH} marginBottom={1}>
            <Text color={theme.text.secondary}>
              {t('Model')}: {modelName}
            </Text>
            <Box flexGrow={1} justifyContent="flex-end">
              <Text color={theme.text.secondary}>
                {t('Context window')}: {formatTokens(contextWindowSize)}{' '}
                {t('tokens')}
              </Text>
            </Box>
          </Box>
          {/* Progress bar — three segments: used | free | buffer */}
          <Box width={CONTENT_WIDTH}>
            <ProgressBar
              usedPercentage={Math.min(percentage, 100)}
              bufferPercentage={
                contextWindowSize > 0
                  ? (breakdown.autocompactBuffer / contextWindowSize) * 100
                  : 0
              }
              width={CONTENT_WIDTH}
            />
          </Box>
          <Box height={1} />
          {/* Legend — same layout as CategoryRow for alignment */}
          <CategoryRow
            symbol={FILLED}
            label={t('Used')}
            tokens={totalTokens}
            contextWindowSize={contextWindowSize}
            symbolColor={theme.text.accent}
          />
          <CategoryRow
            symbol={EMPTY}
            label={t('Free')}
            tokens={breakdown.freeSpace}
            contextWindowSize={contextWindowSize}
            symbolColor={theme.text.secondary}
          />
          <CategoryRow
            symbol={BUFFER}
            label={t('Autocompact buffer')}
            tokens={breakdown.autocompactBuffer}
            contextWindowSize={contextWindowSize}
            symbolColor={theme.status.warning}
          />
          <Box height={1} />

          {/* Breakdown header */}
          <Text bold color={theme.text.primary}>
            {t('Usage by category')}
          </Text>
        </>
      )}

      <CategoryRow
        symbol={FILLED}
        label={t('System prompt')}
        tokens={breakdown.systemPrompt}
        contextWindowSize={contextWindowSize}
        symbolColor={theme.text.accent}
      />
      <CategoryRow
        symbol={FILLED}
        label={t('Built-in tools')}
        tokens={breakdown.builtinTools}
        contextWindowSize={contextWindowSize}
        symbolColor={theme.text.accent}
      />
      {breakdown.mcpTools > 0 && (
        <CategoryRow
          symbol={FILLED}
          label={t('MCP tools')}
          tokens={breakdown.mcpTools}
          contextWindowSize={contextWindowSize}
          symbolColor={theme.text.accent}
        />
      )}
      <CategoryRow
        symbol={FILLED}
        label={t('Memory files')}
        tokens={breakdown.memoryFiles}
        contextWindowSize={contextWindowSize}
        symbolColor={theme.text.accent}
      />
      <CategoryRow
        symbol={FILLED}
        label={t('Skills')}
        tokens={breakdown.skills}
        contextWindowSize={contextWindowSize}
        symbolColor={theme.text.accent}
      />
      {/* Only show Messages when we have real API data */}
      {!isEstimated && (
        <CategoryRow
          symbol={FILLED}
          label={t('Messages')}
          tokens={breakdown.messages}
          contextWindowSize={contextWindowSize}
          symbolColor={theme.text.accent}
        />
      )}

      {showDetails ? (
        <>
          {/* Built-in tools detail */}
          {sortedBuiltinTools.length > 0 && (
            <Box flexDirection="column" marginTop={1}>
              <Text bold color={theme.text.primary}>
                {t('Built-in tools')}
              </Text>
              {sortedBuiltinTools.map((tool) => (
                <DetailRow
                  key={tool.name}
                  name={tool.name}
                  tokens={tool.tokens}
                />
              ))}
            </Box>
          )}

          {/* MCP Tools detail */}
          {sortedMcpTools.length > 0 && (
            <Box flexDirection="column" marginTop={1}>
              <Text bold color={theme.text.primary}>
                {t('MCP tools')}
              </Text>
              {sortedMcpTools.map((tool) => (
                <DetailRow
                  key={tool.name}
                  name={tool.name}
                  tokens={tool.tokens}
                />
              ))}
            </Box>
          )}

          {/* Memory files detail */}
          {sortedMemoryFiles.length > 0 && (
            <Box flexDirection="column" marginTop={1}>
              <Text bold color={theme.text.primary}>
                {t('Memory files')}
              </Text>
              {sortedMemoryFiles.map((file) => (
                <DetailRow
                  key={file.path}
                  name={file.path}
                  tokens={file.tokens}
                />
              ))}
            </Box>
          )}

          {/* Skills detail */}
          {sortedSkills.length > 0 && (
            <Box flexDirection="column" marginTop={1}>
              <Text bold color={theme.text.primary}>
                {t('Skills')}
              </Text>
              {sortedSkills.map((skill) => (
                <Box key={skill.name} flexDirection="column">
                  <Box width={CONTENT_WIDTH} paddingLeft={2}>
                    <Text color={theme.text.secondary}>{'\u2514'} </Text>
                    <Box width={32}>
                      <Text color={theme.text.link}>
                        {truncateName(skill.name, DETAIL_NAME_MAX_LEN)}
                      </Text>
                      {skill.loaded && (
                        <Text color={theme.status.success}> {t('active')}</Text>
                      )}
                    </Box>
                    <Box flexGrow={1} justifyContent="flex-end">
                      <Text color={theme.text.secondary}>
                        {formatTokens(skill.tokens)} {t('tokens')}
                      </Text>
                    </Box>
                  </Box>
                  {skill.loaded &&
                    skill.bodyTokens != null &&
                    skill.bodyTokens > 0 && (
                      <Box width={CONTENT_WIDTH} paddingLeft={4}>
                        <Text color={theme.text.secondary}>{'  \u2514'} </Text>
                        <Box width={30}>
                          <Text color={theme.text.secondary} italic>
                            {t('body loaded')}
                          </Text>
                        </Box>
                        <Box flexGrow={1} justifyContent="flex-end">
                          <Text color={theme.status.success}>
                            +{formatTokens(skill.bodyTokens)} {t('tokens')}
                          </Text>
                        </Box>
                      </Box>
                    )}
                </Box>
              ))}
            </Box>
          )}
        </>
      ) : (
        <Box marginTop={1}>
          <Text color={theme.text.secondary} italic>
            {t('Run /context detail for per-item breakdown.')}
          </Text>
        </Box>
      )}
    </Box>
  );
};
