package Bookmark;

use Moose;

has id    => ( is => 'ro' );
has uri   => ( is => 'rw' );
has title => ( is => 'rw' );
has ctime => ( is => 'ro' );
has mtime => (
    is => 'ro',
    # mtime defaults to ctime
    default => sub { $_[0]->ctime },
    lazy => 1,
);
has tags  => ( is => 'rw' );
has bookmark_uri => ( is => 'rw' );

sub BUILD {
    my $self = shift;
    my $args = shift;
    if ($args->{base_uri}) {
        $self->bookmark_uri(URI->new_abs($self->id, $args->{base_uri}));
    }
}

sub TO_JSON {
    my $self = shift;
    return {
        id    => $self->id,
        uri   => $self->uri,
        title => $self->title,
        ctime => $self->ctime,
        mtime => $self->mtime,
        tags  => $self->tags,
        ($self->bookmark_uri ? (bookmark_uri => $self->bookmark_uri->canonical->as_string) : ()),
    };
}

sub update {
    my $self = shift;
    # TODO: store the dbh somewhere better, or use a more generic "Bookmark Store" object
    my $dbh = shift;
    my $mtime = time;

    my $changed_uri = 0;
    my $sth_current = $dbh->prepare('select uri from bookmarks where id = ?');
    $sth_current->execute($self->id);
    my ($stored_uri) = $sth_current->fetchrow_array;

    if ($stored_uri ne $self->uri) {
        # the URI has changed
        my $sth_update_uri = $dbh->prepare('update resources set uri = ? where uri = ?');
        $sth_update_uri->execute($self->uri, $stored_uri);
        $changed_uri++;
    }

    # update the title
    # TODO: only do this if the title has changed
    # TODO: should we update mtime if the title changes?
    my $sth_update = $dbh->prepare('update resources set title = ? where uri = ?');
    $sth_update->execute($self->title, $self->uri);

    # update the tags
    my $changed_tags = 0;
    my %new_tags = map { $_ => 1 } @{ $self->tags };
    my $sth_delete_tag = $dbh->prepare('delete from tags where uri = ? and tag = ?');
    my $sth_insert_tag = $dbh->prepare('insert into tags (uri, tag) values (?, ?)');
    my $sth_current_tags = $dbh->prepare('select tag from tags where uri = ?');
    $sth_current_tags->execute($self->uri);
    while (my ($tag) = $sth_current_tags->fetchrow_array) {
        if (!$new_tags{$tag}) {
            # if a current tag is not in the new tags, remove it from the database
            $sth_delete_tag->execute($self->uri, $tag);
            $changed_tags++;
        } else {
            # if a new tag is already in the database, remove it from the list of tags to add
            delete $new_tags{$tag};
        }
    }
    for my $tag (keys %new_tags) {
        $sth_insert_tag->execute($self->uri, $tag);
        $changed_tags++;
    }

    if ($changed_uri or $changed_tags) {
        # update the mtime if the bookmark already existed but the tags were changed
        my $sth_update = $dbh->prepare('update bookmarks set mtime = ? where uri = ?');
        $sth_update->execute($mtime, $self->uri);
    }

    # return the bookmark
    return $self;
}

# module return
1;
