use strict;
use warnings;

use Test::More;
use File::Temp qw(tempdir);
use Cwd qw(getcwd);
use File::Path qw(make_path);
use Developer::Dashboard::JSON qw(json_decode);
use Developer::Dashboard::SeedSync ();

use lib 'lib';

use Developer::Dashboard::Collector;
use Developer::Dashboard::CollectorRunner;
use Developer::Dashboard::Config;
use Developer::Dashboard::FileRegistry;
use Developer::Dashboard::PathRegistry;
use Developer::Dashboard::UpdateManager;

my $repo = getcwd();
local $ENV{HOME} = tempdir(CLEANUP => 1);
local $ENV{DEVELOPER_DASHBOARD_RUNTIME_LAYERS} = $ENV{HOME} . '/.developer-dashboard';
local $ENV{DEVELOPER_DASHBOARD_BOOKMARKS}      = $ENV{HOME} . '/.developer-dashboard/dashboards';
local $ENV{DEVELOPER_DASHBOARD_CONFIGS}        = $ENV{HOME} . '/.developer-dashboard/config';

my $paths = Developer::Dashboard::PathRegistry->new;
my $files = Developer::Dashboard::FileRegistry->new(paths => $paths);
my $config = Developer::Dashboard::Config->new(files => $files, paths => $paths);
my $collector = Developer::Dashboard::Collector->new(paths => $paths);
my $runner = Developer::Dashboard::CollectorRunner->new(
    collectors => $collector,
    files      => $files,
    paths      => $paths,
);
my $updater = Developer::Dashboard::UpdateManager->new(
    config => $config,
    files  => $files,
    paths  => $paths,
    runner => $runner,
);

chdir $repo or die $!;
my $result = $updater->run;
ok(ref($result) eq 'ARRAY', 'update returns array of step results');
ok(@$result >= 3, 'all update steps executed');

ok(-f $files->global_config, 'global config written');
is_deeply( json_decode( $files->read('global_config') ), {}, 'update bootstrap creates an empty config.json instead of seeding example collectors' );
ok(-f $paths->dashboards_root . '/api-dashboard', 'api-dashboard page written');
ok(-f $paths->dashboards_root . '/sql-dashboard', 'sql-dashboard page written');
ok(!-f $paths->dashboards_root . '/welcome', 'welcome page is no longer written');
ok(-f $paths->config_root . '/shell/bashrc.sh', 'shell bootstrap written');

my $stale_sql_dashboard = <<'BOOKMARK';
TITLE: SQL Dashboard
:--------------------------------------------------------------------------------:
BOOKMARK: sql-dashboard
:--------------------------------------------------------------------------------:
HTML: <div id="stale-sql-dashboard">stale update copy</div>
BOOKMARK
my $stale_sql_path = $paths->dashboards_root . '/sql-dashboard';
open my $stale_sql_fh, '>:raw', $stale_sql_path or die "Unable to write $stale_sql_path: $!";
print {$stale_sql_fh} $stale_sql_dashboard;
close $stale_sql_fh or die "Unable to close $stale_sql_path: $!";
my $seed_manifest_path = $paths->config_root . '/seeded-pages.json';
make_path( $paths->config_root ) if !-d $paths->config_root;
open my $seed_manifest_fh, '>:raw', $seed_manifest_path or die "Unable to write $seed_manifest_path: $!";
print {$seed_manifest_fh} qq|{"sql-dashboard":{"asset":"sql-dashboard.page","md5":"|
  . Developer::Dashboard::SeedSync::content_md5($stale_sql_dashboard)
  . qq|"}}\n|;
close $seed_manifest_fh or die "Unable to close $seed_manifest_path: $!";

my $refresh_result = $updater->run;
ok( ref($refresh_result) eq 'ARRAY', 'update rerun still returns the step results array after a stale managed seed is present' );
open my $refreshed_sql_fh, '<:raw', $stale_sql_path or die "Unable to read $stale_sql_path: $!";
my $refreshed_sql_dashboard = do { local $/; <$refreshed_sql_fh> };
close $refreshed_sql_fh or die "Unable to close $stale_sql_path: $!";
unlike( $refreshed_sql_dashboard, qr/stale update copy/, 'update rerun refreshes a stale dashboard-managed sql-dashboard saved page' );
like( $refreshed_sql_dashboard, qr/data-sql-workspace-tab="run"/, 'update rerun refreshes the current SQL workspace subtab layout into sql-dashboard' );
like( $refreshed_sql_dashboard, qr/id="sql-table-filter"/, 'update rerun refreshes the current schema filter UI into sql-dashboard' );

done_testing;

__END__

=head1 NAME

04-update-manager.t - update manager tests

=head1 DESCRIPTION

This test verifies update script execution and runtime bootstrap behavior.

=for comment FULL-POD-DOC START

=head1 PURPOSE

Test file in the Developer Dashboard codebase. This file tests the runtime update manager flow.
Open this file when you need the implementation, regression coverage, or runtime entrypoint for that responsibility rather than guessing which part of the tree owns it.

=head1 WHY IT EXISTS

It exists to enforce the TDD contract for this behaviour, stop regressions from shipping, and keep the mandatory coverage and release gates honest.

=head1 WHEN TO USE

Use this file when you are reproducing or fixing behaviour in its area, when you want a focused regression check before the full suite, or when you need to extend coverage without waiting for every unrelated test.

=head1 HOW TO USE

Run it directly with C<prove -lv t/04-update-manager.t> while iterating, then keep it green under C<prove -lr t> before release. Add or update assertions here before changing the implementation that it covers.

=head1 WHAT USES IT

It is used by developers during TDD, by the full C<prove -lr t> suite, by coverage runs, and by release verification before commit or push.

=head1 EXAMPLES

  prove -lv t/04-update-manager.t

Run that command while working on the behaviour this test owns, then rerun C<prove -lr t> before release.

=for comment FULL-POD-DOC END

=cut
