import sys
import os
import argparse

# Force output buffering off so Electron gets real-time status prints
sys.stdout.reconfigure(line_buffering=True)

print("[STATUS] Importing libraries...")
try:
    import torch
    from torchvision import transforms
    from PIL import Image
    from transformers import AutoModelForImageSegmentation
except Exception as e:
    print(f"[ERROR] Dependency import failed: {str(e)}", file=sys.stderr)
    sys.exit(1)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--input', required=True, help='Path to input image')
    parser.add_argument('--output', required=True, help='Path to save output image')
    parser.add_argument('--model', default='ZhengPeng7/BiRefNet', help='BiRefNet model name')
    parser.add_argument('--device', default='auto', help='Device (cuda, cpu, auto)')
    args = parser.parse_args()

    if not os.path.exists(args.input):
        print(f"[ERROR] Input file {args.input} does not exist", file=sys.stderr)
        sys.exit(1)

    print("[STATUS] Detecting device...")
    if args.device == 'auto':
        device = 'cuda' if torch.cuda.is_available() else 'cpu'
    else:
        device = args.device
    print(f"[STATUS] Using device: {device.upper()}")

    print("[STATUS] Loading BiRefNet model (this may take a moment on first run)...")
    try:
        # Load the model with trust_remote_code=True
        model = AutoModelForImageSegmentation.from_pretrained(args.model, trust_remote_code=True)
        model.to(device)
        model.eval()
    except Exception as e:
        print(f"[ERROR] Failed to load model: {str(e)}", file=sys.stderr)
        sys.exit(1)

    print("[STATUS] Loading and preprocessing image...")
    try:
        orig_img = Image.open(args.input)
        
        # Keep original image color profile and transparency if any, but convert to RGB for model
        if orig_img.mode != 'RGB':
            img = orig_img.convert('RGB')
        else:
            img = orig_img

        # BiRefNet works best with 1024x1024 input
        transform_image = transforms.Compose([
            transforms.Resize((1024, 1024)),
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ])
        
        input_tensor = transform_image(img).unsqueeze(0).to(device)
    except Exception as e:
        print(f"[ERROR] Failed to preprocess image: {str(e)}", file=sys.stderr)
        sys.exit(1)

    print("[STATUS] Running background removal inference...")
    try:
        with torch.no_grad():
            preds = model(input_tensor)[-1].sigmoid().cpu()
        
        pred = preds[0].squeeze()
    except Exception as e:
        print(f"[ERROR] Inference failed: {str(e)}", file=sys.stderr)
        sys.exit(1)

    print("[STATUS] Generating transparency mask...")
    try:
        # Resize mask back to original image size
        mask = transforms.ToPILImage()(pred).resize(orig_img.size, Image.Resampling.BILINEAR)

        # Convert original image to RGBA and set the transparency alpha channel
        rgba_img = orig_img.convert("RGBA")
        rgba_img.putalpha(mask)
    except Exception as e:
        print(f"[ERROR] Mask generation failed: {str(e)}", file=sys.stderr)
        sys.exit(1)

    print(f"[STATUS] Saving output transparent image...")
    try:
        # Create output directory if it doesn't exist
        out_dir = os.path.dirname(args.output)
        if out_dir and not os.path.exists(out_dir):
            os.makedirs(out_dir)
            
        rgba_img.save(args.output, "PNG")
    except Exception as e:
        print(f"[ERROR] Failed to save output image: {str(e)}", file=sys.stderr)
        sys.exit(1)

    print("[STATUS] DONE")

if __name__ == '__main__':
    main()
