use std::{fs::File, io::Write};

use aarch64_define::{KIMAGE_START, PAGE_SIZE, THREAD_STACK_SIZE};

use crate::{MkLinker, MlError, Result};

pub(crate) fn arch_write_linker(file: &mut File, config: &MkLinker) -> Result<()> {
    writeln!(file, "OUTPUT_ARCH(aarch64)").map_err(|_| MlError::FsError)?;
    writeln!(file, "ENTRY(_text)").map_err(|_| MlError::FsError)?;
    let start_offset = KIMAGE_START + config.offset;
    writeln!(file, "KIMAGE_VADDR = {start_offset:#x};").map_err(|_| MlError::FsError)?;
    writeln!(file, "PAGE_SIZE = {PAGE_SIZE:#x};").map_err(|_| MlError::FsError)?;
    writeln!(file, "THREAD_STACK_SIZE = {THREAD_STACK_SIZE:#x};").map_err(|_| MlError::FsError)?;
    writeln!(
        file,
        "
SECTIONS
{{
    /DISCARD/ : {{
        *(.eh_frame .eh_frame_hdr)
    }}

    . = KIMAGE_VADDR;

    .head.text : {{
        . = ALIGN(PAGE_SIZE);
        _text = .;
        _stext_idmap = .;
        KEEP(*(.head.text))
        _etext_idmap = .;
    }}

    . = ALIGN(8);
    .text : {{
        _stext = .;
        *(.entry.text)
        . = ALIGN(8);
        *(.text.hot .text .text.[0-9a-zA-Z_]* .text.fixup .text.unlikely)
        . = ALIGN(8);
        *(.fixup)
        *(.gnu.warning)
        *(.got)
        _etext = .;
    }}

    . = ALIGN(PAGE_SIZE);
    .rodata : {{
        _srodata = .;
        *(.rodata) *(.rodata.*)
        _snotes = .;
        KEEP(*(.note.*))
        _enotes = .;
        _erodata = .;
    }}

    .rela : ALIGN(8) {{
        *(.rela .rela*)
    }}

    . = ALIGN(PAGE_SIZE);
    _stack_end = .;
    . += THREAD_STACK_SIZE;
    _stack_top = .;

    . = ALIGN(PAGE_SIZE);
    idmap_pg_dir = .;
    . += PAGE_SIZE * 2;
    idmap_pg_end = .;

    swapper_pg_dir = .;
    . += PAGE_SIZE * 2;
    swapper_pg_end = .;

    . = ALIGN(PAGE_SIZE);
    .data : {{
        _sdata = .;
        *(.data .data.[0-9a-zA-Z_]*)
        _edata = .;
    }}

    . = ALIGN(64);
    .bss : {{
        _sbss = .;
        *(.bss .bss.[0-9a-zA-Z_]*)
        . = ALIGN(64);
        _ebss = .;
    }}
    _end = .;
}}"
    )
    .map_err(|_| MlError::FsError)
}
