package Physics::CVD::Interface::LAMMPS;
use strict;
use warnings;
use Carp;
use File::Path qw(make_path);

# ═══════════════════════════════════════════════════════════════════════════════
# LAMMPS interface for CVD surface reaction MD
#
# Generates scripts for:
#   - Reactive MD with ReaxFF for CVD surface chemistry
#   - Precursor adsorption/decomposition studies
#   - Film stress and relaxation
# ═══════════════════════════════════════════════════════════════════════════════

sub new {
    my ($class, %opts) = @_;
    my $self = bless {
        work_dir   => $opts{work_dir} // './lammps_cvd',
        executable => $opts{executable} // 'lmp',
    }, $class;
    make_path($self->{work_dir}) unless -d $self->{work_dir};
    return $self;
}

# Generate a ReaxFF CVD surface reaction script
sub generate_surface_reaction {
    my ($self, %opts) = @_;
    my $substrate = $opts{substrate} // 'Si';
    my $precursor = $opts{precursor} // 'SiH4';
    my $T         = $opts{temperature} // 700;
    my $potential = $opts{potential} // 'ffield.reax.cho';
    my $n_precursor = $opts{n_molecules} // 20;

    my $script = <<EOF;
# LAMMPS ReaxFF CVD surface reaction — $precursor on $substrate
# Generated by Physics::CVD

units           real
atom_style      charge
boundary        p p f

# Read substrate
read_data       substrate.data

# ReaxFF potential
pair_style      reaxff NULL
pair_coeff      * * $potential Si O H N C

# Groups
group           substrate type 1
group           precursor type 2 3 4

# Fix bottom layer
region          bottom block INF INF INF INF INF 3.0
group           frozen region bottom
fix             freeze frozen setforce 0.0 0.0 0.0

# Thermostat for substrate surface
fix             nvt_sub substrate nvt temp $T $T 100.0

# Integration
timestep        0.5
fix             nve_prec precursor nve

# Charge equilibration
fix             qeq all qeq/reaxff 1 0.0 10.0 1.0e-6 reaxff

# Reflecting wall
fix             wall all wall/reflect zhi EDGE

# Output
thermo          100
thermo_style    custom step temp pe ke etotal press atoms
dump            traj all custom 500 dump.cvd.lammpstrj id type x y z q

# Insert precursor molecules
molecule        prec_mol precursor.mol
region          insert_region block INF INF INF INF 30.0 40.0
fix             depo precursor deposit $n_precursor 0 200 12345 &
                region insert_region mol prec_mol near 3.0 &
                vz -5.0 -3.0

# Run deposition
run             50000

# Relaxation
unfix           depo
run             20000

write_data      final_cvd.data
EOF

    my $filename = "$self->{work_dir}/in.cvd_reaction";
    open my $fh, '>', $filename or croak "Cannot write $filename: $!";
    print $fh $script;
    close $fh;
    return $filename;
}

# Generate film stress analysis script
sub generate_stress_analysis {
    my ($self, %opts) = @_;
    my $T = $opts{temperature} // 300;

    my $script = <<EOF;
# LAMMPS CVD film stress analysis
# Generated by Physics::CVD

units           metal
atom_style      atomic
boundary        p p f

read_data       cvd_film.data

pair_style      tersoff
pair_coeff      * * SiO.tersoff Si O

# NPT relaxation to find equilibrium stress
fix             relax all npt temp $T $T 0.1 x 0.0 0.0 1.0 y 0.0 0.0 1.0

thermo          100
thermo_style    custom step temp press pxx pyy pzz lx ly lz

# Compute per-atom stress
compute         stress all stress/atom NULL
dump            stress all custom 1000 dump.stress id type x y z &
                c_stress[1] c_stress[2] c_stress[3]

run             10000
write_data      relaxed_film.data
EOF

    my $filename = "$self->{work_dir}/in.stress";
    open my $fh, '>', $filename or croak "Cannot write $filename: $!";
    print $fh $script;
    close $fh;
    return $filename;
}

sub run {
    my ($self, %opts) = @_;
    my $input = $opts{input} // 'in.cvd_reaction';
    my $np    = $opts{processors} // 1;
    my $dir   = $self->{work_dir};
    my $exe   = $self->{executable};

    my $cmd = ($np > 1)
        ? "cd $dir && mpirun -np $np $exe -in $input > log.lammps 2>&1"
        : "cd $dir && $exe -in $input > log.lammps 2>&1";

    system($cmd) == 0 or carp "LAMMPS run failed";
    return $self;
}

# Parse LAMMPS log for thermo data
sub parse_log {
    my ($self, $logfile) = @_;
    $logfile //= "$self->{work_dir}/log.lammps";
    open my $fh, '<', $logfile or croak "Cannot read $logfile: $!";

    my @data;
    my $in_thermo = 0;
    my @headers;
    while (<$fh>) {
        if (/^Step\s/) {
            $in_thermo = 1;
            @headers = split;
            next;
        }
        if ($in_thermo && /^Loop time/) {
            $in_thermo = 0;
            next;
        }
        if ($in_thermo && /^\s*\d/) {
            my @vals = split;
            my %row;
            @row{@headers} = @vals;
            push @data, \%row;
        }
    }
    close $fh;
    return \@data;
}

1;
