package Finance::Bank::LloydsTSB::Account;

=head1 NAME

Finance::Bank::LloydsTSB::Account - 

=head1 SYNOPSIS

synopsis

=head1 DESCRIPTION

description

=cut

use strict;
use warnings;

our $VERSION = '1.35';
our $DEBUG = 0;

use Time::Local;

use Finance::Bank::LloydsTSB::Statement;
use Finance::Bank::LloydsTSB::utils qw(debug);

sub ua         { shift->{ua}         }
sub name       { shift->{name}       }
sub descr_num  { shift->{descr_num}  }
sub sort_code  { shift->{sort_code}  }
sub account_no { shift->{account_no} }
sub balance    { shift->{balance}    }
sub parent     { shift->{parent}     }
sub form_index { shift->{form_index} }

sub _on_account_overview_page {
    my $self = shift;
    $self->debug("On account overview page?\n");

    # Notice case difference of 'O' between this and navigation link to
    # this page
    if ($self->ua->content =~ /Account Overview/) {
        $self->debug("yes\n");
        return 1;
    }
    else {
        $self->debug("no\n");
        return 0;
    }
}

sub _navigate_to_account_overview {
    my $self = shift;

    if (! $self->_on_account_overview_page) {
# This is the one we want
#         my @links = $self->ua->find_all_links;
#         my $correct = $links[0]->text;

        # GRR!    gets decoded into \xa0 by HTML::TokeParser
        # (which uses HTML::Entities::decode_entities)
        unless ($self->ua->follow_link(text_regex =>
                                         qr/Account[ \xa0]overview/))
        {
#             my $dumpfile = '/tmp/dump.html';
#             $self->debug("Writing content to $dumpfile\n");
#             $self->ua->save_content($dumpfile);
#             my @context = $self->ua->content =~ /(.{100}overview.{100,}?$)/gims;
#             die "no overview???", $self->ua->content
#               unless @context;
#               map "---\n$_\n---\n", @context;
            die "Couldn't go to account overview page\n";
        }
        $self->debug("Gone to account overview page\n");
    }
}

sub _on_account_details_page {
    my $self = shift;
    $self->debug("On details page for ", $self->name, "?\n");

    if ($self->ua->content !~ /Your account details/) {
        $self->debug("no\n");
        return 0;
    }

    if ($self->_check_selected_account_text) {
        $self->debug("yes\n");
        return 1;
    }

    $self->debug("no\n");
    return 0;
}

sub _check_selected_account_text {
    my $self = shift;

    # Look for a table which has the right 'Selected account' in the
    # header.
    my $te = new HTML::TableExtract;
    $te->parse($self->ua->content);
    foreach my $ts ($te->table_states) {
        my @rows = $ts->rows;
        my $header = $rows[0];
        foreach my $td (@$header) {
            if ($td =~ /Selected account/ && (index($td, $self->{name}) >= 0)) {
                return 1;
            }
        }
    }
    
    return 0;
}

sub _navigate_to_details {
    my $self = shift;
    if ($self->_on_account_details_page) {
        $self->debug("Already on details page for ", $self->name, "\n");
        return;
    }

    if (! $self->_on_account_overview_page) {
        $self->_navigate_to_account_overview;
    }

    $self->ua->follow_link(text => $self->name)
      or die "Couldn't go to account ", $self->name;
    $self->debug("Gone to ", $self->name, " details page\n");
}

sub _on_account_statement_page {
    my $self = shift;
    $self->debug("On account statement page?\n");

    if ($self->ua->content !~ /Your account statement/) {
        $self->debug("no\n");
        return 0;
    }

    if ($self->_check_selected_account_text) {
        $self->debug("yes\n");
        return 1;
    }
    
    $self->debug("yes\n");
    return 1;
}

sub _navigate_to_statement {
    my $self = shift;

    if ($self->_on_account_statement_page) {
        $self->debug("Already on statement page for ", $self->name, "\n");
        return;
    }

    $self->_navigate_to_account_overview;

    if (0) {
      # Go via details page
      $self->_navigate_to_details;
      $self->ua->follow_link(text => 'Statement')
        or die "Couldn't go to statement for ", $self->name;
    }
    else {
      # Go via Options form
      my $form = $self->ua->form_number($self->form_index);
      $self->ua->select('SelectAction', 'statement.ibc');
      my $response = $self->ua->submit_form;
      die "submit of $self->name actions form failed with HTTP code ",
          $response->code, "\n" # also $self->ua->status
        unless $response->is_success; # also $self->ua->success
    }

    $self->debug("Gone to ", $self->name, " statement page\n");
}

sub _on_account_statement_download_page {
    my $self = shift;
    $self->debug("On account statement download page?\n");

    if ($self->ua->content !~ /Download a statement/) {
        $self->debug("no\n");
        return 0;
    }

    if ($self->_check_selected_account_text) {
        $self->debug("yes\n");
        return 1;
    }
    
    $self->debug("yes\n");
    return 1;
}

sub _navigate_to_statement_download {
    my $self = shift;

    if ($self->_on_account_statement_download_page) {
        $self->debug("Already on statement download page for ", $self->name, "\n");
        return;
    }

    $self->_navigate_to_statement;

    # <option value="6">Download a statement</option>
    $self->ua->select("selectbox", 6);

    # This used to work, but now the Go <input> button has name="" :-(
#    $self->ua->click_button(value => "Go");
    $self->ua->submit_form(form_name => "StatementSearch");

    die "Go to download statement failed with HTTP ", $self->ua->status
      unless $self->ua->success;
    $self->debug("Gone to ", $self->name, " statement download page\n");
}

=head2 fetch_statement

Fetches a Finance::Bank::LloydsTSB::Statement object representing the
latest statement page.

=cut

sub fetch_statement {
    my $self = shift;

    $self->_navigate_to_statement;

    my $te = new HTML::TableExtract(
        headers => [
            "Date",
            "Payment Type",
            "Details",
            "Paid Out",
            "Paid In",
            "Balance",
        ]
    );
    (my $html = $self->ua->content) =~ s/&nbsp;/ /g;
    $te->parse($html);
    my @tables = $te->tables;
    die "Couldn't find unique statement table" unless @tables == 1;

    my $DATE_RE = qr/^([ \d]\d)(\w\w\w)(\d\d)$/;

    my @transactions;
    my @fields = qw(date type details out in balance);

  ROW:
    foreach my $row ($tables[0]->rows) {
        my %transaction;
        for my $i (0 .. $#fields) {
            my $field = $fields[$i];
            my $cell = $row->[$i];
            if (ref $cell eq 'SCALAR') {
              $cell = $$cell;
            }
            elsif (ref($cell) =~ /HTML/) {
              $cell = $cell->as_trimmed_text;
            }
            next ROW unless defined $cell;
            $transaction{$field} = $cell;
        }
        next unless $transaction{date} =~ /\S/;
        if ($transaction{date} =~ $DATE_RE) {
            $transaction{dom} = $1;
            $transaction{month} = $2;
            $transaction{year} = $3;
        }
        else {
            warn "transaction date '", $transaction{date}, "' didn't match /$DATE_RE/\n";
        }
        push @transactions, \%transaction;
    }

    return bless({
        transactions => \@transactions,
        start_date   => $transactions[ 0]{date},
        end_date     => $transactions[-1]{date},
    }, 'Finance::Bank::LloydsTSB::Statement');
}

=head2 download_statement($year, $month, $day, $duration)

Downloads a statement in QIF format for time period starting on the
given date, and returns it in a scalar.

Duration options are taken from the website's HTML:

    <option value="1">This date only</option>
    <option value="2">+/- 1 week</option>
    <option value="3">+/- 2 weeks</option>
    <option value="4">+/- 3 weeks</option>
    <option value="5">+ 1 month</option>
    <option value="6">+ 2 months</option>
    <option value="7">+ 3 months</option>

e.g. 5 for 1 month's worth of QIF transactions.

=cut

sub download_statement {
    my $self = shift;
    my ($year, $month, $day, $duration) = @_;

    $self->debug("Downloading statement for $year/$month/$day, duration option $duration\n");
    $self->_navigate_to_statement_download;
    $self->debug("\n");

    $self->ua->set_fields(
        DateYear => $year,
        DateMonth => $month,
        DateDay => $day,
        DateRangeSelection => $duration,
        # radio button, 'DownloadLatest' is the other option
        'Download' => 'DownloadDate',
    );

    $self->ua->select('Format', 104); # download as QIF
    $self->ua->submit_form;
    my $ok = 0;
    my $ct = $self->ua->ct;
    if ($ct eq 'text/x-qif') {
      $self->debug("Got content type $ct\n");
      $ok = 1;
    }
    else {
      warn "Expected content type 'text/x-qif' but got '$ct'\n";
    }
    my $qif = $self->ua->content;

    # For some extremely weird reason, if we do this:

#     # pop .qif download off stack so that we can still use other links
#     $self->debug("Going back a page\n");
#     $self->ua->back; 

    # then $self->ua->follow_link either leads us back to the login
    # page or gets us into a state where we can't do anything.

    # A workaround is to start at the beginning:
    $self->ua->get("https://online.lloydstsb.co.uk/customer.ibc");
    # although this time we don't need to log in.

    return ($ct, $qif);
}

1;