/*
==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--

R1

Copyright (C) 2019-2026  Anonymous

There are several releases over multiple years,
they are listed as ranges, such as: "2019-2026".

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
*/

#![cfg(unix)]

use {
    std::{
        env,
        fs,
        os::{
            linux::net::SocketAddrExt,
            unix::{
                net::{SocketAddr, UnixDatagram},
                prelude::FileTypeExt,
            },
        },
        process::{Command, Stdio},
        thread,
    },
    crate::Result,
    zeros::{
        keccak::Hash,
        prg::Prg,
    },
};

const SERVER_ADDRESS: &[u8] = &[
    0x54, 0xb1, 0x5d, 0xc0, 0x85, 0x2c, 0x11, 0x06,     0x8f, 0x9a, 0x29, 0xff, 0x01, 0xf8, 0xc8, 0xbb,
    0x1a, 0x03, 0xce, 0xa7, 0x6a, 0xf6, 0xdd, 0x1a,     0x6c, 0x4f, 0x5b, 0x2c, 0xf7, 0x4d, 0xd5, 0x87,
    0x9b, 0x29, 0x1b, 0xbb, 0xe8, 0x12, 0xa4, 0x87,     0xaa, 0xf0, 0x03, 0xa3, 0x82, 0x18, 0xb5, 0xbf,
    0xd0, 0x2d, 0xa6, 0x96, 0x06, 0x2c, 0xff, 0x4e,     0x6e, 0xc4, 0xaa, 0x59, 0x41, 0x2b, 0xcd, 0x60,
];

pub fn spawn_focus_thread_if_needed<B>(namaste_id: B, pid: u32) where B: AsRef<[u8]> {
    if let Ok(true) = is_it() {
        let namaste_id = namaste_id.as_ref().to_vec();
        thread::spawn(move || {
            if let Err(err) = (|| -> Result<()> {
                let address = make_server_address(namaste_id)?;
                let socket = UnixDatagram::bind_addr(&address)?;
                let mut buf = [u8::MIN; 1];
                loop {
                    if let Ok(_) = socket.recv_from(&mut buf) {
                        let mut cmd = Command::new("swaymsg");
                        cmd.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
                        cmd.arg(format!("[pid={pid}]")).arg("focus");
                        cmd.spawn()?;
                    }
                }
            })() {
                eprintln!("{}", err);
            }
        });
    }
}

pub fn try_to_focus_last_proc<B>(namaste_id: B) -> Result<()> where B: AsRef<[u8]> {
    let socket = UnixDatagram::bind_addr(&SocketAddr::from_abstract_name(Prg::make()?.next_chunk::<64>())?)?;
    socket.send_to_addr(&[u8::MIN], &make_server_address(namaste_id)?)?;
    Ok(())
}

fn make_server_address<B>(namaste_id: B) -> Result<SocketAddr> where B: AsRef<[u8]> {
    SocketAddr::from_abstract_name(Hash::Sha3_512.hash([namaste_id.as_ref(), SERVER_ADDRESS]))
}

fn is_it() -> Result<bool> {
    if let Ok(path) = env::var("SWAYSOCK") {
        return Ok(fs::metadata(path)?.file_type().is_socket());
    }
    Ok(false)
}
