using UnityEngine;
using Mirror;

public class PlayerController : NetworkBehaviour
{
    // =======================
    // Movement Parameters
    // =======================
    [Header("Movement Parameters")]
    public float moveSpeed = 5f;
    public float acceleration = 10f;
    public float deceleration = 10f;

    // =======================
    // Jump Parameters
    // =======================
    [Header("Jump Parameters")]
    public float maxJumpHeight = 4f;
    public float timeToJumpApex = 0.4f;
    public int extraJumps = 1;

    // =======================
    // Jump Timing
    // =======================
    [Header("Jump Timing")]
    public float coyoteTime = 0.2f;
    public float jumpBufferTime = 0.2f;

    // =======================
    // Fall Parameters
    // =======================
    [Header("Fall Parameters")]
    public float maxFallSpeed = 20f;

    // =======================
    // Ledge Detection
    // =======================
    [Header("Ledge Detection")]
    public Transform groundCheck;
    public float groundCheckRadius = 0.1f;
    public LayerMask groundLayer;
    public Transform wallCheck;
    public float wallCheckDistance = 0.1f;

    // =======================
    // Private Variables
    // =======================
    private Rigidbody2D rb;
    private bool isFacingRight = true;

    private bool isGrounded;
    private bool isTouchingWall;
    private bool canDoubleJump;
    private float coyoteTimeCounter;
    private float jumpBufferCounter;

    private float jumpVelocity;
    private float gravity;

    // Input variables
    private float moveInput;
    private bool jumpPressed;
    private bool jumpHeld;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();

        // Calculate gravity and jump velocity based on desired jump height and time to apex
        gravity = (-2 * maxJumpHeight) / Mathf.Pow(timeToJumpApex, 2);
        rb.gravityScale = gravity / Physics2D.gravity.y; // Adjust gravity scale relative to Unity's default gravity
        jumpVelocity = Mathf.Abs(gravity) * timeToJumpApex;
    }

    void Update()
    {
        if (!isLocalPlayer) return;

        // Handle input
        HandleInput();

        // Update timers
        if (isGrounded)
        {
            coyoteTimeCounter = coyoteTime;
            canDoubleJump = extraJumps > 0;
        }
        else
        {
            coyoteTimeCounter -= Time.deltaTime;
        }

        if (jumpPressed)
        {
            jumpBufferCounter = jumpBufferTime;
        }
        else
        {
            if (jumpBufferCounter > 0)
                jumpBufferCounter -= Time.deltaTime;
        }

        // Handle jumping with Jump Buffering and Coyote Time
        if (jumpBufferCounter > 0f && coyoteTimeCounter > 0f)
        {
            PerformJump();
            jumpBufferCounter = 0f; // Reset jump buffer after jumping
        }
    }

    void FixedUpdate()
    {
        if (!isLocalPlayer) return;

        // Check ground and wall status
        isGrounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayer);
        isTouchingWall = Physics2D.Raycast(wallCheck.position, transform.right, wallCheckDistance, groundLayer);

        // Apply horizontal movement with acceleration and deceleration
        float targetSpeed = moveInput * moveSpeed;
        float speedDifference = targetSpeed - rb.velocity.x;
        float accelRate = (Mathf.Abs(targetSpeed) > 0.01f) ? acceleration : deceleration;
        float movement = Mathf.Pow(Mathf.Abs(speedDifference) * accelRate, 0.9f) * Mathf.Sign(speedDifference);
        rb.AddForce(movement * Vector2.right);

        // Clamp fall speed
        if (rb.velocity.y < -maxFallSpeed)
        {
            rb.velocity = new Vector2(rb.velocity.x, -maxFallSpeed);
        }

        // Variable jump height
        if (rb.velocity.y > 0 && !jumpHeld)
        {
            rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * 0.5f);
        }

        // Flip character based on movement direction
        if (moveInput > 0 && !isFacingRight)
            Flip();
        else if (moveInput < 0 && isFacingRight)
            Flip();
    }

    /// <summary>
    /// Handles player input. Replace placeholders with mobile input handling.
    /// </summary>
    void HandleInput()
    {
        moveInput = 0f;

        foreach (Touch touch in Input.touches)
        {
            switch (touch.phase)
            {
                case TouchPhase.Began:
                    // Define touch regions or gestures for jumping and moving
                    if (IsJumpArea(touch.position))
                    {
                        jumpPressed = true;
                    }
                    break;

                case TouchPhase.Moved:
                case TouchPhase.Stationary:
                    if (IsJumpArea(touch.position))
                    {
                        jumpHeld = true;
                    }
                    break;

                case TouchPhase.Ended:
                case TouchPhase.Canceled:
                    if (IsJumpArea(touch.position))
                    {
                        jumpHeld = false;
                    }
                    break;
            }
        }

        // Implement horizontal movement based on swipe or joystick
        // Example: Swipe left/right to move
        // moveInput = DetectSwipeDirection();
    }

    /// <summary>
    /// Determines if a touch position is within the jump area.
    /// Customize this method based on your game's UI layout.
    /// </summary>
    bool IsJumpArea(Vector2 touchPosition)
    {
        // Example: Define bottom-right quarter of the screen as the jump area
        return touchPosition.x > Screen.width * 0.75f && touchPosition.y < Screen.height * 0.25f;
    }

    /// <summary>
    /// Detects swipe direction for horizontal movement.
    /// Implement based on your preferred control scheme.
    /// </summary>
    float DetectSwipeDirection()
    {
        // Placeholder for swipe detection logic
        return 0f;
    }

    /// <summary>
    /// Executes the jump logic, including double jumps.
    /// </summary>
    void PerformJump()
    {
        if (isGrounded || coyoteTimeCounter > 0f)
        {
            rb.velocity = new Vector2(rb.velocity.x, jumpVelocity);
            // Optionally, trigger jump animation or sound here
        }
        else if (canDoubleJump && !isGrounded)
        {
            rb.velocity = new Vector2(rb.velocity.x, jumpVelocity);
            canDoubleJump = false;
        }
    }

    /// <summary>
    /// Flips the character's orientation.
    /// </summary>
    void Flip()
    {
        isFacingRight = !isFacingRight;
        Vector3 localScale = transform.localScale;
        localScale.x *= -1;
        transform.localScale = localScale;
    }

    /// <summary>
    /// Visualize ground and wall checks in the Scene view.
    /// </summary>
    void OnDrawGizmosSelected()
    {
        if (groundCheck != null)
        {
            Gizmos.color = Color.green;
            Gizmos.DrawWireSphere(groundCheck.position, groundCheckRadius);
        }

        if (wallCheck != null)
        {
            Gizmos.color = Color.red;
            Gizmos.DrawLine(wallCheck.position, wallCheck.position + transform.right * wallCheckDistance);
        }
    }
}



add mobil control right and left button and jump button