<?php
namespace PrimeLink\Modules\Imports\DataSources;

if ( ! defined( 'ABSPATH' ) ) { exit; }

final class GoogleDriveSource implements DataSourceInterface {

    private $settings = array();

    public function __construct( array $settings = array() ) {
        $this->settings = $settings;
    }

    public function handle( array $payload ) {
        $api_key = $this->settings['gdrive_api_key'] ?? '';
        $access_token = $this->settings['gdrive_access_token'] ?? '';
        
        // Prefer OAuth access token over API key
        if ( ! $access_token && ! $api_key ) {
            return array( 'error' => 'Google Drive authentication required. Please authenticate with Google Drive in Settings → Integrations.' );
        }

        $file_input = $payload['file'] ?? ( $payload['path'] ?? ( $this->settings['gdrive_default_file'] ?? '' ) );
        $file_input = trim( (string) $file_input );
        if ( ! $file_input ) {
            return array( 'error' => 'No Google Drive file ID or link provided.' );
        }

        $file_id = $this->extract_file_id( $file_input );
        if ( ! $file_id ) {
            return array( 'error' => 'Invalid Google Drive file link or ID.' );
        }

        // Fetch metadata to get name and mime type
        $meta = $this->fetch_metadata( $file_id, $api_key, $access_token );
        if ( isset( $meta['error'] ) ) {
            return $meta;
        }

        $name = $meta['name'] ?? ( $file_id . '.csv' );
        $mime = $meta['mimeType'] ?? '';

        // Download content
        $content = $this->download_file( $file_id, $api_key, $access_token );
        if ( isset( $content['error'] ) ) {
            return $content;
        }

        $upload_dir = wp_upload_dir();
        $dest_dir   = trailingslashit( $upload_dir['basedir'] ) . 'primelink/';
        $dest_url   = trailingslashit( $upload_dir['baseurl'] ) . 'primelink/';
        if ( ! \PrimeLink\Helpers\FilesystemHelper::directory_exists( $dest_dir ) ) {
            \PrimeLink\Helpers\FilesystemHelper::create_directory( $dest_dir );
        }

        $sanitized_name = sanitize_file_name( $name ?: ( $file_id . '.csv' ) );
        $dest_name      = time() . '-' . $sanitized_name;
        $dest_path      = $dest_dir . $dest_name;

        \PrimeLink\Helpers\FilesystemHelper::write_file( $dest_path, $content['body'] );

        $ext  = strtolower( pathinfo( $sanitized_name, PATHINFO_EXTENSION ) );
        $type = $this->map_type( $ext, $mime );

        return array(
            'path'          => $dest_path,
            'url'           => $dest_url . $dest_name,
            'type'          => $type,
            'original_name' => $sanitized_name,
            'source'        => 'gdrive',
            'downloaded_at' => current_time( 'mysql' ),
        );
    }

    private function extract_file_id( $input ) {
        // If looks like ID (no spaces and short), return it
        if ( preg_match( '#^[a-zA-Z0-9_-]{10,}$#', $input ) ) {
            return $input;
        }
        // Try to extract from URL patterns
        if ( preg_match( '#/d/([^/]+)/#', $input, $m ) ) {
            return $m[1];
        }
        if ( preg_match( '#id=([^&]+)#', $input, $m ) ) {
            return $m[1];
        }
        return '';
    }

    private function fetch_metadata( $file_id, $api_key, $access_token = '' ) {
        $url = 'https://www.googleapis.com/drive/v3/files/' . rawurlencode( $file_id ) . '?fields=name,mimeType';
        
        $headers = array();
        if ( $access_token ) {
            $headers['Authorization'] = 'Bearer ' . $access_token;
        } elseif ( $api_key ) {
            $url .= '&key=' . rawurlencode( $api_key );
        }
        
        $res = \PrimeLink\Helpers\HttpHelper::get( $url, array(
            'headers'     => $headers,
            'timeout'     => 30,
            'retry'       => 1,
            'retry_delay' => 1,
        ) );
        if ( ! $res['success'] ) {
            return array( 'error' => $res['error'] ?? 'Failed to fetch metadata from Google Drive.' );
        }
        $code = $res['code'];
        $body = json_decode( $res['body'], true );
        if ( $code < 200 || $code > 299 ) {
            $msg = $body['error']['message'] ?? 'Google Drive metadata error.';
            // If 404 or 403 and we only have API key, suggest making file public or using OAuth
            if ( ( $code === 404 || $code === 403 ) && $api_key && ! $client_id ) {
                $msg .= ' API Key can only access public files. For private files, you need to either: 1) Make the file public (share with "Anyone with the link"), or 2) Use OAuth 2.0 authentication with Client ID.';
            } elseif ( ( $code === 404 || $code === 403 ) && $client_id ) {
                $msg .= ' This file appears to be private. API Key can only access public files. For private files, OAuth 2.0 authentication is required. Please ensure the file is shared publicly or configure OAuth authentication.';
            }
            return array( 'error' => $msg );
        }
        return $body;
    }

    private function download_file( $file_id, $api_key, $access_token = '' ) {
        $url = 'https://www.googleapis.com/drive/v3/files/' . rawurlencode( $file_id ) . '?alt=media';
        
        $headers = array();
        if ( $access_token ) {
            $headers['Authorization'] = 'Bearer ' . $access_token;
        } elseif ( $api_key ) {
            $url .= '&key=' . rawurlencode( $api_key );
        }
        
        $res = \PrimeLink\Helpers\HttpHelper::get( $url, array(
            'headers'     => $headers,
            'timeout'     => 60,
            'retry'       => 1,
            'retry_delay' => 1,
        ) );
        if ( ! $res['success'] ) {
            return array( 'error' => $res['error'] ?? 'Failed to download from Google Drive.' );
        }
        $code = $res['code'];
        if ( $code < 200 || $code > 299 ) {
            $body = json_decode( $res['body'], true );
            $msg  = $body['error']['message'] ?? 'Google Drive download failed.';
            // If 404 or 403 and we only have API key, suggest making file public or using OAuth
            if ( ( $code === 404 || $code === 403 ) && $api_key && ! $client_id ) {
                $msg .= ' API Key can only access public files. For private files, you need to either: 1) Make the file public (share with "Anyone with the link"), or 2) Use OAuth 2.0 authentication with Client ID.';
            } elseif ( ( $code === 404 || $code === 403 ) && $client_id ) {
                $msg .= ' This file appears to be private. API Key can only access public files. For private files, OAuth 2.0 authentication is required. Please ensure the file is shared publicly or configure OAuth authentication.';
            }
            return array( 'error' => $msg );
        }
        return array( 'body' => $res['body'] );
    }

    private function map_type( $ext, $mime ) {
        $map = array(
            'xml'  => 'xml',
            'csv'  => 'csv',
            'xlsx' => 'xlsx',
            'xls'  => 'xlsx',
            'json' => 'json',
        );
        if ( isset( $map[ $ext ] ) ) {
            return $map[ $ext ];
        }
        if ( $mime ) {
            if ( false !== strpos( $mime, 'xml' ) ) return 'xml';
            if ( false !== strpos( $mime, 'sheet' ) ) return 'xlsx';
            if ( false !== strpos( $mime, 'csv' ) ) return 'csv';
            if ( false !== strpos( $mime, 'json' ) ) return 'json';
        }
        return 'csv';
    }
}
