#!/usr/bin/perl -w

#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
#    02110-1301, USA

package Finance::Quote::TMX;

use strict;
use warnings;

use constant DEBUG => $ENV{DEBUG};
use if DEBUG, 'Smart::Comments';

use HTTP::Request;
use LWP::UserAgent;
use JSON qw( decode_json encode_json );
use String::Util qw(trim);

our $VERSION = '1.52'; # VERSION

our @labels = qw/name cap year_range currency exchange symbol ask bid high last low open close isodate date/;

sub labels {
  return ( tmx => \@labels );
}

sub methods {
  return ( tmx    => \&tmx,
           canada => \&tmx );
}

sub tmx {
  my $quoter  = shift;
  my @symbols = @_;
  my $ua      = $quoter->user_agent();
  my %info;

  foreach my $symbol (@_) {
    eval {
      my $url     = 'https://app-money.tmx.com/graphql';
      my $header  = ["accept"           =>           "*/*",
                     "accept-language"  => "en-US,en;q=0.9",
                     "authorization"    => "",
                     "content-type"     => "application/json",
                     "locale"           => "en",
                     "sec-ch-ua"        => "\"Google Chrome\";v=\"87\", \" Not;A Brand\";v=\"99\", \"Chromium\";v=\"87\"",
                     "sec-ch-ua-mobile" => "?0",
                     "sec-fetch-dest"   => "empty",
                     "sec-fetch-mode"   => "cors",
                     "sec-fetch-site"   => "same-site"];
      my $body   = "{\"operationName\":\"getQuoteBySymbol\",\"variables\":{\"symbol\":\"$symbol\",\"locale\":\"en\"},\"query\":\"query getQuoteBySymbol(\$symbol: String, \$locale: String) {\\n  getQuoteBySymbol(symbol: \$symbol, locale: \$locale) {\\n    symbol\\n    name\\n    price\\n    priceChange\\n    percentChange\\n    exchangeName\\n    exShortName\\n    exchangeCode\\n    marketPlace\\n    sector\\n    industry\\n    volume\\n    openPrice\\n    dayHigh\\n    dayLow\\n    MarketCap\\n    MarketCapAllClasses\\n    peRatio\\n    prevClose\\n    dividendFrequency\\n    dividendYield\\n    dividendAmount\\n    dividendCurrency\\n    beta\\n    eps\\n    exDividendDate\\n    shortDescription\\n    longDescription\\n    website\\n    email\\n    phoneNumber\\n    fullAddress\\n    employees\\n    shareOutStanding\\n    totalDebtToEquity\\n    totalSharesOutStanding\\n    sharesESCROW\\n    vwap\\n    dividendPayDate\\n    weeks52high\\n    weeks52low\\n    alpha\\n    averageVolume10D\\n    averageVolume30D\\n    averageVolume50D\\n    priceToBook\\n    priceToCashFlow\\n    returnOnEquity\\n    returnOnAssets\\n    day21MovingAvg\\n    day50MovingAvg\\n    day200MovingAvg\\n    dividend3Years\\n    dividend5Years\\n    datatype\\n    __typename\\n  }\\n}\\n\"}";

      
      my $request = HTTP::Request->new('POST', $url, $header, $body);
      $request->header("referrer"       => "https://money.tmx.com/",
                       "referrerPolicy" => "strict-origin-when-cross-origin",
                       "mode"           =>  "cors");

      my $reply     = $ua->request($request);
      
      ### Search   : $url, $reply->code
      ### reply    : $reply->content
      
      my $data      = decode_json $reply->content;

      die "Unexpected result" unless exists $data->{data}
                              and    exists $data->{data}->{getQuoteBySymbol};
      
      $data = $data->{data}->{getQuoteBySymbol};

      die "Unexpected symbol" unless lc($data->{symbol}) eq lc($symbol);

      ### data     : $data

      $info{$symbol, 'name'}       = $data->{name};
      $info{$symbol, 'exchange'}   = $data->{exchangeName};
      $info{$symbol, 'volume'}     = $data->{volume};
      $info{$symbol, 'open'}       = $data->{openPrice};
      $info{$symbol, 'high'}       = $data->{dayHigh};
      $info{$symbol, 'low'}        = $data->{dayLow};
      $info{$symbol, 'cap'}        = $data->{MarketCap};
      $info{$symbol, 'close'}      = $data->{prevClose};
      $info{$symbol, 'year_range'} = $data->{weeks52low} . ' - ' . $data->{weeks52high};
      $info{$symbol, 'symbol'}     = $data->{symbol};

      $info{$symbol, 'success'} = 1;
    };
    
    if ($@) {
      my $error = "TMX failed: $@";
      $info{$symbol, 'success'}  = 0;
      $info{$symbol, 'errormsg'} = trim($error);
    }
  }

  return wantarray() ? %info : \%info;
}

1;

=head1 NAME

Finance::Quote::TSX - Obtain quotes from the Toronto Stock Exchange 
(https://money.tmx.com)

=head1 SYNOPSIS

    use Finance::Quote;

    $q = Finance::Quote->new;

    %stockinfo = $q->fetch('tmx','NT-T');   # Only query TMX
    %stockinfo = $q->fetch('canada','NT');  # Failover to other Canadian sources

=head1 DESCRIPTION

This module obtains information from the Toronto Stock Exchange,
https://money.tmx.com.

This module is loaded by default on a Finance::Quote object. It's also
possible to load it explicitly by placing 'TMX' in the argument list to
Finance::Quote->new().

=head1 LABELS RETURNED

The following labels are returned by Finance::Quote::TMX: name,
exchange, volume, open, high, low, cap, close, year_range, symbol

=head1 TERMS & CONDITIONS

Use of money.tmx.com is governed by any terms & conditions of that
site and its data provider quotemedia.com.

Finance::Quote is released under the GNU General Public License, version 2,
which explicitly carries a "No Warranty" clause.

=cut
