include "dropins";

import "lib/typeLib" as typeLib;
import "lib/argsLib" as argsLib;
import "lib/stringLib" as stringLib;
import "lib/tableLib" as tableLib;
import "lib/utilsLib" as utilsLib;
import "lib/journalLib" as journalLib;
import "lib/journalTypes" as journalTypes;

import "journalUtils" as journalUtils;

def printExperienceStats($stats; $substanceFilter; $consumerFilter; $withTitle):
  . as $experience |

  ($consumerFilter // ["default"]) as $consumerFilter |

  $experience.ingestions | 
    journalLib::filterIngestions($substanceFilter; $consumerFilter) | 
    sort_by(.sortDate) as $ingestions |

  ($ingestions | journalLib::ingestionsSubstanceNames) as $substanceNames |
  ($ingestions | journalLib::ingestionsByConsumer) as $ingestionsByConsumer |

  "" as $experienceStatsText |
  $experienceStatsText | 
    if $withTitle then 
      . += ($experience | journalUtils::formatExperienceTitle | . + "\n")
    end | . as $experienceStatsText |

  ($ingestionsByConsumer | keys) as $consumerNames |
  reduce $consumerNames[] as $consumerName ($experienceStatsText;
    . as $experienceStatsText |
    $experienceStatsText |
      if ($consumerNames != ["default"]) 
        then . += "Consumer: \($consumerName)\n"
      end | . as $experienceStatsText  |

    ($ingestionsByConsumer[$consumerName] | journalLib::ingestionsSubstanceNames) as $consumerSubstanceNames |

    $experienceStatsText | reduce $substanceNames[] as $substanceName (.; 
      . as $experienceStatsText |

      ($stats.[$consumerName].[$substanceName] | keys) as $ingestionMethods |

      ($experienceStatsText | . += "Substance: \($substanceName)\n") as $experienceStatsText |

      reduce ($stats.[$consumerName].[$substanceName] | to_entries)[] as $ingestionMethodInfo ($experienceStatsText;
        . as $experienceStatsText |

        $ingestionMethodInfo |
        .key as $ingestionMethod |
        .value as $ingestionInfo |

        $experienceStatsText | 
          . += "Dose (\($ingestionMethod | stringLib::titleCase)): \($ingestionInfo | journalUtils::formatIngestionInfo)\n" |
          . as $experienceStatsText | 
          
        $experienceStatsText
      ) | . as $experienceStatsText |

      $experienceStatsText | if ($ingestionMethods | length > 1) then 
        ($stats | journalLib::statsCalculateCombinedDose($substanceName; $consumerName)) as $combinedDose |
        . += "Combined Dose: \($combinedDose.dose // "Unknown") \($combinedDose.unit)\n" 
      end | . as $experienceStatsText |

      $experienceStatsText | . += "\n"
    )
  ) | rtrimstr("\n\n");

def printExperienceLog($customUnits; $substanceFilter; $consumerFilter; $pretty; $withTitle):
  . as $experience |
  ($consumerFilter // ["default"]) as $consumerFilter |

  $experience.ingestions | 
    journalLib::filterIngestions($substanceFilter; $consumerFilter) | 
    sort_by(.sortDate) as $ingestions |

  $ingestions | journalLib::ingestionsConsumerNames as $consumerNames |

  if ($consumerNames != ["default"]) then
    ["Substance", "Dose", "ROA", "Consumer", "Time"]
  else 
    ["Substance", "Dose", "ROA", "Time"]
  end | . as $columnTitles |

  [
    $ingestions[] as $ingestion |
      $ingestion |
      .substanceName as $substanceName |
      journalLib::ingestionConsumerName as $consumerName |
      journalUtils::formatIngestionDose($customUnits) as $doseText |
      journalUtils::formatIngestionROA($customUnits) as $roaText |
      journalUtils::formatIngestionTime as $timeText |
      if ($consumerNames != ["default"])
      then [$substanceName, $doseText, $roaText, $consumerName, $timeText]
      else [$substanceName, $doseText, $roaText, $timeText] end
  ] as $rows |

  tableLib::printPrettyTable(
    if $withTitle then ($experience | journalUtils::formatExperienceTitle) else null end;
    $columnTitles;
    $rows
  );

def printExperiences($customUnits; $substanceFilter; $consumerFilter):
  . as $experiences |

  $experiences |
    .[] as $entry |
      $entry.experience as $experience |
      $entry.stats as $stats |
      ($experience | printExperienceLog(
        $customUnits; 
        $substanceFilter; 
        $consumerFilter; 
        true;
        true
      )) + 
      "\nCumulative Doses:\n" +
      ($experience | printExperienceStats(
        $stats; 
        $substanceFilter;
        $consumerFilter;
        false
      )) + "\n";


def main:
  def usage:
    [
      "psychonaut_journal_stats {printExperience,printExperiences}",
      ""
    ] | join("\n") | halt_error(1);

  $ARGS.named["exportFile"][0] as $exportData |
  $exportData | journalTypes::ensureExportData |

  ($ARGS | argsLib::parseArgs) as $parsedArgs |

  $parsedArgs.nonArgs[0] as $program |
  ($parsedArgs | .nonArgs |= $parsedArgs.nonArgs[1:]) as $parsedArgs |

  if $program == null then
    if any($parsedArgs.shortArgs[]; . == "h") then usage end |
    if ($parsedArgs.longArgs | has("help")) then usage end |

    usage
  elif $program == "printExperience" then 
    def printExperienceUsage($reason):
      [
        $reason,
        "Usage: printExperience [experienceTitle] --title=bool --stats=bool --substance-filter=[substanceNames,] --consumer-filter=[consumerNames,]",
        ""
      ] | map(select(. != null))  | join("\n") | halt_error(1);

    if any($parsedArgs.shortArgs[]; . == "h") then printExperienceUsage(null) end |
    if ($parsedArgs.longArgs | has("help")) then printExperienceUsage(null) end |

    $parsedArgs.nonArgs[0] as $experienceTitle |
    if $experienceTitle == null then printExperienceUsage("experienceTitle not provided") end |

    {
      substanceFilter: null,
      consumerFilter: null,
      withTitle: true,
      withStats: true,
    } as $defaultOptions |
    $defaultOptions as $options |

    reduce ($parsedArgs.longArgs | to_entries[]) as $longArg ($options; (
      $longArg.key as $arg |
      $longArg.value as $value |

      if $arg == "title" then
        .withTitle |= ($value // $defaultOptions.withTitle | argsLib::parseArgBool)
      end |
      if $arg == "stats" then
        .withStats |= ($value // $defaultOptions.withStats | argsLib::parseArgBool)
      end |
      if $arg == "substance-filter" then
        .substanceFilter |= ($parsedArgs.longArgs.["substance-filter"] | split(","))
      end |
      if $arg == "consumer-filter" then
        .consumerFilter |= ($parsedArgs.longArgs.["consumer-filter"] | split(","))
      end
    )) | . as $options |

    $exportData.experiences | journalLib::experienceByTitle($experienceTitle) as $experience |
    if $experience == null then error("Experience not found") end | 

    ($experience | printExperienceLog(
      $exportData.customUnits;
      $options.substanceFilter;
      $options.consumerFilter;
      $options.pretty;
      $options.withTitle
    )) as $ingestionLog | 
    
    if $options.withStats then 
      ($experience | journalLib::experienceStats($exportData.customUnits)) as $stats |
      $ingestionLog + 
        "\n\nCumulative Doses:\n" +
        ($experience | printExperienceStats(
          $stats; 
          $options.substanceFilter;
          $options.consumerFilter;
          false
        ))
    else 
      $ingestionLog
    end
  elif $program == "printExperiences" then 
    def printExperiencesUsage($reason):
      [
        $reason,
        "Usage: printExperiences --substance-filter=[substanceNames,]  --consumer-filter=[consumerNames,] --sort-method={old-to-new,highest-combined-dose,highest-dose-for-method} --sort-option-substance-name=[string] --sort-options-ingestion-method=[string] --sort-options-consumer-name=[string]  --sort-filter={firstN(x),reverse}",
        ""
      ] | map(select(. != null))  | join("\n") | halt_error(1);

    if any($parsedArgs.shortArgs[]; . == "h") then printExperiencesUsage(null) end |
    if ($parsedArgs.longArgs | has("help")) then printExperiencesUsage(null) end |

    {
      substanceFilter: null,
      consumerFilter: null,
      sortMethod: "old-to-new",
      sortOptions: {},
      sortFilter: null
    } as $defaultOptions |
    $defaultOptions as $options |

    reduce ($parsedArgs.longArgs | to_entries[]) as $longArg ($options; (
      $longArg.key as $arg |
      $longArg.value as $value |
      if $arg == "substance-filter" then
        .substanceFilter |= ($parsedArgs.longArgs.["substance-filter"] | split(","))
      end |
      if $arg == "consumer-filter" then
        .consumerFilter |= ($parsedArgs.longArgs.["consumer-filter"] | split(","))
      end |
      if $arg == "sort-method" then
        .sortMethod |= $parsedArgs.longArgs.["sort-method"]
      end |
      if $arg == "sort-option-substance-name" then
        .sortOptions.substanceName |= $parsedArgs.longArgs.["sort-option-substance-name"]
      end |
      if $arg == "sort-option-ingestion-method" then
        .sortOptions.ingestionMethod |= $parsedArgs.longArgs.["sort-option-ingestion-method"]
      end |
      if $arg == "sort-option-consumer-name" then
        .sortOptions.consumerName |= $parsedArgs.longArgs.["sort-option-consumer-name"]
      end |
      if $arg == "sort-filter" then
        .sortFilter |= $parsedArgs.longArgs.["sort-filter"]
      end
    )) | . as $options |

    $exportData.experiences |
      journalLib::filterSortExperiences(
        $exportData.customUnits;
        $options.substanceFilter;
        $options.consumerFilter;
        $options.sortMethod;
        $options.sortOptions
      ) |
      if ($options.sortFilter != null) then utilsLib::sortFilterFromString($options.sortFilter) end | 
      printExperiences(
        $exportData.customUnits;
        $options.substanceFilter;
        $options.consumerFilter
      )
  else
    usage
  end;