program bpress;

{$mode objfpc}{$H+}

uses
  Classes, SysUtils, StrUtils, Clipbrd, DateUtils, Interfaces,
  LCLProc, LazUTF8;

type
  TBloodPressure = record
    Systolic: Integer;
    Diastolic: Integer;
    Pulse: Integer;
  end;

var
  Sets: array[1..10] of TBloodPressure;
  SetCount: Integer = 0;

function CustomDateStr: string;
const
  DayNames: array[1..7] of string = ('SUN','MON','TUE','WED','THU','FRI','SAT');
var
  y, r: Integer;
  dow: string;
begin
  y := YearOf(Now);
  r := y - 2018; // 令和年号計算
  dow := DayNames[DayOfWeek(Now)];
  Result := Format('%dR%2.2d-', [y, r]) +
            FormatDateTime('mmdd-', Now) +
            dow + '-' +
            FormatDateTime('hhnn', Now);
end;

function C(const S: string): string;
begin
  Result := UTF8ToConsole(S);
end;

procedure ParseBP(const Line: string; out BP: TBloodPressure);
var
  Raw, S, P: string;
  SlashPos, SpacePos: SizeInt;
begin
  Raw := Line;

  if Raw <> Trim(Raw) then
    raise Exception.Create('No leading/trailing spaces allowed. Format: 150/89 98');

  SpacePos := Pos(' ', Raw);
  if (SpacePos = 0) or (PosEx(' ', Raw, SpacePos + 1) <> 0) then
    raise Exception.Create('Exactly one space required. Format: 150/89 98');

  S := Copy(Raw, 1, SpacePos - 1);
  P := Copy(Raw, SpacePos + 1, MaxInt);

  SlashPos := Pos('/', S);
  if (SlashPos = 0) or (PosEx('/', S, SlashPos + 1) <> 0) then
    raise Exception.Create('Use one slash only. Format: 150/89 98');

  if (SlashPos = 1) or (SlashPos = Length(S)) then
    raise Exception.Create('Systolic and diastolic values required. Format: 150/89 98');

  if not TryStrToInt(Copy(S, 1, SlashPos - 1), BP.Systolic) then
    raise Exception.Create('Invalid systolic value.');
  if not TryStrToInt(Copy(S, SlashPos + 1, MaxInt), BP.Diastolic) then
    raise Exception.Create('Invalid diastolic value.');
  if not TryStrToInt(P, BP.Pulse) then
    raise Exception.Create('Invalid pulse value.');
end;

procedure ShowAverageTwo(Index1, Index2: Integer);
var
  BP1, BP2: TBloodPressure;
  Avg: TBloodPressure;
  Diff: TBloodPressure;
  avgLine: string;
begin
  BP1 := Sets[Index1];
  BP2 := Sets[Index2];

  Writeln('calc...');
  Writeln(Format('%d/%d %d', [BP1.Systolic, BP1.Diastolic, BP1.Pulse]));
  Writeln(Format('%d/%d %d', [BP2.Systolic, BP2.Diastolic, BP2.Pulse]));

  Diff.Systolic := Abs(BP1.Systolic - BP2.Systolic);
  Diff.Diastolic := Abs(BP1.Diastolic - BP2.Diastolic);
  Diff.Pulse := Abs(BP1.Pulse - BP2.Pulse);
  Writeln(Format('%d/%d %d', [Diff.Systolic, Diff.Diastolic, Diff.Pulse]));

  // 平均値(小数)を文字列にして "=" の長さを合わせる
  avgLine := Format('%.1f/%.1f %.1f',
    [(BP1.Systolic + BP2.Systolic) / 2,
     (BP1.Diastolic + BP2.Diastolic) / 2,
     (BP1.Pulse + BP2.Pulse) / 2]);

  Writeln(StringOfChar('=', Length(avgLine)));
  Writeln(avgLine);

  Avg.Systolic := Round((BP1.Systolic + BP2.Systolic) / 2);
  Avg.Diastolic := Round((BP1.Diastolic + BP2.Diastolic) / 2);
  Avg.Pulse := Round((BP1.Pulse + BP2.Pulse) / 2);

  Writeln(Format('%d/%d %d', [Avg.Systolic, Avg.Diastolic, Avg.Pulse]));
  Writeln('...end');
end;

procedure ShowAverageRange(i1, i2: Integer);
var
  sumSys, sumDia, sumPulse, count, idx: Integer;
begin
  sumSys := 0; sumDia := 0; sumPulse := 0; count := 0;
  for idx := i1 to i2 do
  begin
    sumSys   := sumSys   + Sets[idx].Systolic;
    sumDia   := sumDia   + Sets[idx].Diastolic;
    sumPulse := sumPulse + Sets[idx].Pulse;
    Inc(count);
  end;

  Writeln('calc...');
  Writeln(Format('%.1f/%.1f %.1f',
    [sumSys / count, sumDia / count, sumPulse / count]));
  Writeln(Format('%d/%d %d',
    [Round(sumSys / count), Round(sumDia / count), Round(sumPulse / count)]));
  Writeln('...end');
end;

procedure CopyForDocument;
var
  avgLine: string;
  Output: TStringList;
begin
  Output := TStringList.Create;
  Writeln('Copy to Clipboard for Document...');
  try
    Output.Add(CustomDateStr);
    Output.Add(Format('%d/%d %d', [Sets[1].Systolic, Sets[1].Diastolic, Sets[1].Pulse]));
    Output.Add(Format('%d/%d %d', [Sets[2].Systolic, Sets[2].Diastolic, Sets[2].Pulse]));
    Output.Add(Format('%d/%d %d',
      [Abs(Sets[1].Systolic - Sets[2].Systolic),
       Abs(Sets[1].Diastolic - Sets[2].Diastolic),
       Abs(Sets[1].Pulse - Sets[2].Pulse)]));

    avgLine := Format('%.1f/%.1f %.1f',
      [(Sets[1].Systolic + Sets[2].Systolic) / 2,
       (Sets[1].Diastolic + Sets[2].Diastolic) / 2,
       (Sets[1].Pulse + Sets[2].Pulse) / 2]);

    Output.Add(StringOfChar('=', Length(avgLine)));
    Output.Add(avgLine);  // ← ここだけでOK
    Output.Add(Format('%d/%d %d',
      [Round((Sets[1].Systolic + Sets[2].Systolic) / 2),
       Round((Sets[1].Diastolic + Sets[2].Diastolic) / 2),
       Round((Sets[1].Pulse + Sets[2].Pulse) / 2)]));

    Writeln(Output.Text);
    Clipboard.AsText := Output.Text;
  finally
    Output.Free;
  end;
end;

procedure CopyForWeb;
var
  Avg: TBloodPressure;
  Output: TStringList;
begin
  Avg.Systolic := Round((Sets[1].Systolic + Sets[2].Systolic) / 2);
  Avg.Diastolic := Round((Sets[1].Diastolic + Sets[2].Diastolic) / 2);
  Avg.Pulse := Round((Sets[1].Pulse + Sets[2].Pulse) / 2);

  Output := TStringList.Create;
  Writeln('Copy to Clipboard for Webpage…');
  try
    Output.Add(CustomDateStr);
    Output.Add(Format('%d/%d %d。', [Avg.Systolic, Avg.Diastolic, Avg.Pulse]));

    Writeln(Output.Text);
    Clipboard.AsText := Output.Text;
  finally
    Output.Free;
  end;
end;

procedure WatchSets;
var
  i: Integer;
begin
  Writeln('Saved blood pressure sets:');
  if SetCount = 0 then
    Writeln('(no data)')
  else
    for i := 1 to SetCount do
      Writeln(Format('Set %d: %d/%d %d',
        [i, Sets[i].Systolic, Sets[i].Diastolic, Sets[i].Pulse]));
end;

procedure ShowHelpEnglish;
begin
  Writeln('bpress console tool - commands:');
  Writeln('  --set N        : Enter blood pressure data for set number N');
  Writeln('  --average N-M  : Calculate average between set N to M');
  Writeln('                   (if N-M covers 2 sets, show differences too)');
  Writeln('  --copyd        : Copy document-style output to clipboard');
  Writeln('  --copyw        : Copy webpage-style output to clipboard');
  Writeln('  --watch-sets   : Show all saved blood pressure sets');
  Writeln('  --help         : Show this help message (English)');
  Writeln('  --hj           : Show help message (Japanese)');
  Writeln('exit             : Quit the program');
end;

procedure ShowHelpJapanese;
begin
  Writeln(C('bpress コンソールツール - コマンド一覧:'));
  Writeln(C('  --set N        : セット番号 N に血圧データを入力します'));
  Writeln(C('  --average N-M  : セット N から M の平均値を計算します'));
  Writeln(C('                   (N-M が 2つのセットなら差分も表示します)'));
  Writeln(C('  --copyd        : ドキュメント用の詳細出力をクリップボードにコピーします'));
  Writeln(C('  --copyw        : Webページ用の簡易出力をクリップボードにコピーします'));
  Writeln(C('  --watch-sets   : 保存されたすべての血圧データを表示します'));
  Writeln(C('  --help         : 英語のヘルプを表示します'));
  Writeln(C('  --hj           : 日本語のヘルプを表示します'));
  Writeln(C('exit             : プログラムを終了します'));
end;

var
  Line, Cmd, Param: string;
  i1, i2: Integer;

begin
  Writeln('  --help         : Show this help message (English)');
  Writeln('  --hj           : Show help message (Japanese)');

  while True do
  begin
    Write('$');
    ReadLn(Line);

    if Pos(' ', Line) > 0 then
    begin
      Cmd := LowerCase(Trim(Copy(Line, 1, Pos(' ', Line) - 1)));
      Param := Trim(Copy(Line, Pos(' ', Line) + 1, MaxInt));
    end
    else
    begin
      Cmd := LowerCase(Trim(Line));
      Param := '';
    end;

    if (Cmd = 'bpress') or (Cmd = '$bpress') then
    begin
      if StartsStr('--set', Param) then
      begin
        Delete(Param, 1, 5);
        i1 := StrToInt(Trim(Param));
        WriteLn('Enter blood pressure (e.g., 150/89 98):');
        ReadLn(Line);
        try
          ParseBP(Line, Sets[i1]);
          if i1 > SetCount then
            SetCount := i1;
        except
          on E: Exception do
          begin
            Writeln(C('入力エラー:形式が正しくありません。例: 150/89 98'));
            Writeln(C('詳細: ') + C(E.Message));
          end;
        end;
      end
      else if StartsStr('--average', Param) then
      begin
        Delete(Param, 1, 9);
        if Param = '' then
          Writeln('Usage: bpress --average N-M')
        else if Pos('-', Param) > 0 then
        begin
          i1 := StrToInt(Trim(Copy(Param, 1, Pos('-', Param) - 1)));
          i2 := StrToInt(Trim(Copy(Param, Pos('-', Param) + 1, MaxInt)));

          if (i1 < 1) or (i2 > SetCount) or (i1 > i2) then
            Writeln('Invalid range.')
          else if (i2 - i1 + 1 = 2) then
            ShowAverageTwo(i1, i2)
          else
            ShowAverageRange(i1, i2);
        end
        else
          Writeln('Usage: bpress --average N-M');
      end
      else if (Param = '--copyd') then
        CopyForDocument
      else if (Param = '--copyw') then
        CopyForWeb
      else if (Param = '--watch-sets') then
        WatchSets
      else if (Param = '--help') then
        ShowHelpEnglish
      else if (Param = '--hj') then
        ShowHelpJapanese
      else
        Writeln('Unknown command.');
    end
    else if (Cmd = 'exit') or (Cmd = '$exit') then
      Break
    else
      Writeln('Invalid input.');
  end;
end.